Properly handling different test cases at the same time.¶
import unittest, doctest, re, inspect, typing, types, contextlib
Sample test methods.¶
def test_me(): assert True
class TestClass(unittest.TestCase):
def test_this(self): assert False
Methods¶
Combine unittest and doctest
suites.¶
def make_test_suite(*objects: typing.Union[
unittest.TestCase, types.FunctionType, str
]) -> unittest.TestSuite:
Create a test suite from a few different objects.
suite, doctest_suite = unittest.TestSuite(), doctest.DocTestSuite()
suite.addTest(doctest_suite)
for object in objects:
if isinstance(object, type) and issubclass(object, unittest.TestCase):
Load unittest.TestCase
when that type is encountered.
suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(object))
elif isinstance(object, str):
In the case of strings we’ll use the doctest
module to find standard doctests and inline markdown code.
doctest_suite.addTest(doctest.DocTestCase(doctest.DocTestParser().get_doctest(object, globals(), __name__, __name__, 0)))
doctest_suite.addTest(doctest.DocTestCase(InlineDoctestParser().get_doctest(object, globals(), __name__, __name__, 0), checker=NullOutputCheck))
elif inspect.isfunction(object):
When a function is encountered create a test case from that.
suite.addTest(unittest.FunctionTestCase(object))
return suite
Run the main test suite¶
def run(suite: unittest.TestCase) -> unittest.TestResult:
run
a test suite likely created from make_test_suite.
result = unittest.TestResult(); suite.run(result)
if result.failures:
sys.stderr.writelines((str(result) + '\n' + '\n'.join(msg for text, msg in result.failures)).splitlines(True))
return result
class NullOutputCheck(doctest.OutputChecker):
A compatability tool for tests as long as they don’t return an exception.
def check_output(self, *e): return True
A doctest
parser for inline code objects.¶
class InlineDoctestParser(doctest.DocTestParser):
In "pidgy"
, we want all code to compute. Specifically we add the ability to run
inline markdown code objects. as tests.
_EXAMPLE_RE = re.compile(r'`(?P<indent>\s{0})'
r'(?P<source>[^`].*?)'
r'`')
def _parse_example(self, m, name, lineno): return m.group('source'), None, "...", None
Running the examples.¶
Running some made up tests.
result = run(make_test_suite("""What is the `range`
>>> 10
10
""", test_me, TestClass))
Expected output.¶
<unittest.result.TestResult run=4 errors=0 failures=1>
Traceback (most recent call last):
File "<ipython-input-31-5ae775417371>", line 10, in test_this
def test_this(self): assert False
AssertionError