Coverage for /usr/local/lib/python3.7/site-packages/_pytest/unittest.py : 5%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1""" discovery and running of std-library "unittest" style tests. """
2import sys
3import traceback
5import _pytest._code
6import pytest
7from _pytest.compat import getimfunc
8from _pytest.config import hookimpl
9from _pytest.outcomes import exit
10from _pytest.outcomes import fail
11from _pytest.outcomes import skip
12from _pytest.outcomes import xfail
13from _pytest.python import Class
14from _pytest.python import Function
15from _pytest.runner import CallInfo
18def pytest_pycollect_makeitem(collector, name, obj):
19 # has unittest been imported and is obj a subclass of its TestCase?
20 try:
21 if not issubclass(obj, sys.modules["unittest"].TestCase):
22 return
23 except Exception:
24 return
25 # yes, so let's collect it
26 return UnitTestCase(name, parent=collector)
29class UnitTestCase(Class):
30 # marker for fixturemanger.getfixtureinfo()
31 # to declare that our children do not support funcargs
32 nofuncargs = True
34 def collect(self):
35 from unittest import TestLoader
37 cls = self.obj
38 if not getattr(cls, "__test__", True):
39 return
41 skipped = getattr(cls, "__unittest_skip__", False)
42 if not skipped:
43 self._inject_setup_teardown_fixtures(cls)
44 self._inject_setup_class_fixture()
46 self.session._fixturemanager.parsefactories(self, unittest=True)
47 loader = TestLoader()
48 foundsomething = False
49 for name in loader.getTestCaseNames(self.obj):
50 x = getattr(self.obj, name)
51 if not getattr(x, "__test__", True):
52 continue
53 funcobj = getimfunc(x)
54 yield TestCaseFunction(name, parent=self, callobj=funcobj)
55 foundsomething = True
57 if not foundsomething:
58 runtest = getattr(self.obj, "runTest", None)
59 if runtest is not None:
60 ut = sys.modules.get("twisted.trial.unittest", None)
61 if ut is None or runtest != ut.TestCase.runTest:
62 yield TestCaseFunction("runTest", parent=self)
64 def _inject_setup_teardown_fixtures(self, cls):
65 """Injects a hidden auto-use fixture to invoke setUpClass/setup_method and corresponding
66 teardown functions (#517)"""
67 class_fixture = _make_xunit_fixture(
68 cls, "setUpClass", "tearDownClass", scope="class", pass_self=False
69 )
70 if class_fixture:
71 cls.__pytest_class_setup = class_fixture
73 method_fixture = _make_xunit_fixture(
74 cls, "setup_method", "teardown_method", scope="function", pass_self=True
75 )
76 if method_fixture:
77 cls.__pytest_method_setup = method_fixture
80def _make_xunit_fixture(obj, setup_name, teardown_name, scope, pass_self):
81 setup = getattr(obj, setup_name, None)
82 teardown = getattr(obj, teardown_name, None)
83 if setup is None and teardown is None:
84 return None
86 @pytest.fixture(scope=scope, autouse=True)
87 def fixture(self, request):
88 if getattr(self, "__unittest_skip__", None):
89 reason = self.__unittest_skip_why__
90 pytest.skip(reason)
91 if setup is not None:
92 if pass_self:
93 setup(self, request.function)
94 else:
95 setup()
96 yield
97 if teardown is not None:
98 if pass_self:
99 teardown(self, request.function)
100 else:
101 teardown()
103 return fixture
106class TestCaseFunction(Function):
107 nofuncargs = True
108 _excinfo = None
109 _testcase = None
111 def setup(self):
112 self._testcase = self.parent.obj(self.name)
113 self._obj = getattr(self._testcase, self.name)
114 if hasattr(self, "_request"):
115 self._request._fillfixtures()
117 def teardown(self):
118 self._testcase = None
119 self._obj = None
121 def startTest(self, testcase):
122 pass
124 def _addexcinfo(self, rawexcinfo):
125 # unwrap potential exception info (see twisted trial support below)
126 rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo)
127 try:
128 excinfo = _pytest._code.ExceptionInfo(rawexcinfo)
129 # invoke the attributes to trigger storing the traceback
130 # trial causes some issue there
131 excinfo.value
132 excinfo.traceback
133 except TypeError:
134 try:
135 try:
136 values = traceback.format_exception(*rawexcinfo)
137 values.insert(
138 0,
139 "NOTE: Incompatible Exception Representation, "
140 "displaying natively:\n\n",
141 )
142 fail("".join(values), pytrace=False)
143 except (fail.Exception, KeyboardInterrupt):
144 raise
145 except: # noqa
146 fail(
147 "ERROR: Unknown Incompatible Exception "
148 "representation:\n%r" % (rawexcinfo,),
149 pytrace=False,
150 )
151 except KeyboardInterrupt:
152 raise
153 except fail.Exception:
154 excinfo = _pytest._code.ExceptionInfo.from_current()
155 self.__dict__.setdefault("_excinfo", []).append(excinfo)
157 def addError(self, testcase, rawexcinfo):
158 try:
159 if isinstance(rawexcinfo[1], exit.Exception):
160 exit(rawexcinfo[1].msg)
161 except TypeError:
162 pass
163 self._addexcinfo(rawexcinfo)
165 def addFailure(self, testcase, rawexcinfo):
166 self._addexcinfo(rawexcinfo)
168 def addSkip(self, testcase, reason):
169 try:
170 skip(reason)
171 except skip.Exception:
172 self._skipped_by_mark = True
173 self._addexcinfo(sys.exc_info())
175 def addExpectedFailure(self, testcase, rawexcinfo, reason=""):
176 try:
177 xfail(str(reason))
178 except xfail.Exception:
179 self._addexcinfo(sys.exc_info())
181 def addUnexpectedSuccess(self, testcase, reason=""):
182 self._unexpectedsuccess = reason
184 def addSuccess(self, testcase):
185 pass
187 def stopTest(self, testcase):
188 pass
190 def _handle_skip(self):
191 # implements the skipping machinery (see #2137)
192 # analog to pythons Lib/unittest/case.py:run
193 testMethod = getattr(self._testcase, self._testcase._testMethodName)
194 if getattr(self._testcase.__class__, "__unittest_skip__", False) or getattr(
195 testMethod, "__unittest_skip__", False
196 ):
197 # If the class or method was skipped.
198 skip_why = getattr(
199 self._testcase.__class__, "__unittest_skip_why__", ""
200 ) or getattr(testMethod, "__unittest_skip_why__", "")
201 self._testcase._addSkip(self, self._testcase, skip_why)
202 return True
203 return False
205 def runtest(self):
206 if self.config.pluginmanager.get_plugin("pdbinvoke") is None:
207 self._testcase(result=self)
208 else:
209 # disables tearDown and cleanups for post mortem debugging (see #1890)
210 if self._handle_skip():
211 return
212 self._testcase.debug()
214 def _prunetraceback(self, excinfo):
215 Function._prunetraceback(self, excinfo)
216 traceback = excinfo.traceback.filter(
217 lambda x: not x.frame.f_globals.get("__unittest")
218 )
219 if traceback:
220 excinfo.traceback = traceback
223@hookimpl(tryfirst=True)
224def pytest_runtest_makereport(item, call):
225 if isinstance(item, TestCaseFunction):
226 if item._excinfo:
227 call.excinfo = item._excinfo.pop(0)
228 try:
229 del call.result
230 except AttributeError:
231 pass
233 unittest = sys.modules.get("unittest")
234 if unittest and call.excinfo and call.excinfo.errisinstance(unittest.SkipTest):
235 # let's substitute the excinfo with a pytest.skip one
236 call2 = CallInfo.from_call(
237 lambda: pytest.skip(str(call.excinfo.value)), call.when
238 )
239 call.excinfo = call2.excinfo
242# twisted trial support
245@hookimpl(hookwrapper=True)
246def pytest_runtest_protocol(item):
247 if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules:
248 ut = sys.modules["twisted.python.failure"]
249 Failure__init__ = ut.Failure.__init__
250 check_testcase_implements_trial_reporter()
252 def excstore(
253 self, exc_value=None, exc_type=None, exc_tb=None, captureVars=None
254 ):
255 if exc_value is None:
256 self._rawexcinfo = sys.exc_info()
257 else:
258 if exc_type is None:
259 exc_type = type(exc_value)
260 self._rawexcinfo = (exc_type, exc_value, exc_tb)
261 try:
262 Failure__init__(
263 self, exc_value, exc_type, exc_tb, captureVars=captureVars
264 )
265 except TypeError:
266 Failure__init__(self, exc_value, exc_type, exc_tb)
268 ut.Failure.__init__ = excstore
269 yield
270 ut.Failure.__init__ = Failure__init__
271 else:
272 yield
275def check_testcase_implements_trial_reporter(done=[]):
276 if done:
277 return
278 from zope.interface import classImplements
279 from twisted.trial.itrial import IReporter
281 classImplements(TestCaseFunction, IReporter)
282 done.append(1)