Source code for testplan.testing.pyunit

"""PyUnit test runner."""

import unittest
from typing import Generator, Dict

from testplan.testing import base as testing
from testplan.testing.multitest.entries import assertions
from testplan.testing.multitest.entries import schemas
from testplan.testing.multitest.entries import base as entries_base
from testplan.report import (
    TestGroupReport,
    TestCaseReport,
    ReportCategories,
    RuntimeStatus,
)


[docs] class PyUnitConfig(testing.TestConfig): """ Configuration object for :py:class`~testplan.testing.pyunit.PyUnit` test runner. """
[docs] @classmethod def get_options(cls): return {"testcases": [type(unittest.TestCase)]}
[docs] class PyUnit(testing.Test): """ Test runner for PyUnit unit tests. :param name: Test instance name, often used as uid of test entity. :type name: ``str`` :param testcases: PyUnit testcases. :type testcases: :py:class:`~unittest.TestCase` :param description: Description of test instance. :type description: ``str`` Also inherits all :py:class:`~testplan.testing.base.Test` options. """ CONFIG = PyUnitConfig _TESTCASE_NAME = "PyUnit test results" def __init__(self, name, testcases, description=None, **kwargs): super(PyUnit, self).__init__( name=name, testcases=testcases, description=description, **kwargs ) self._pyunit_testcases = { testcase.__name__: testcase for testcase in self.cfg.testcases }
[docs] def add_main_batch_steps(self): """Specify the test steps: run the tests, then log the results.""" self._add_step(self.run_tests) self._add_step(self.log_test_results)
[docs] def run_tests(self): """Run PyUnit and wait for it to terminate.""" with self.report.timer.record("run"): self.result.report.extend(self._run_tests())
[docs] def get_test_context(self): """ Currently we do not inspect individual PyUnit testcases - only allow the whole suite to be run. """ return [ (testcase, [testcase]) for testcase in self._pyunit_testcases.keys() ]
def _dry_run_testsuites(self): for pyunit_testcase in self.cfg.testcases: testsuite_report = TestGroupReport( name=pyunit_testcase.__name__, uid=pyunit_testcase.__name__, category=ReportCategories.TESTSUITE, entries=[ TestCaseReport( name=self._TESTCASE_NAME, uid=self._TESTCASE_NAME ) ], ) self.result.report.append(testsuite_report)
[docs] def run_testcases_iter( self, testsuite_pattern: str = "*", testcase_pattern: str = "*", shallow_report: Dict = None, ) -> Generator: """ Run all testcases and yield testcase reports. :param testsuite_pattern: pattern to match for testsuite names :param testcase_pattern: pattern to match for testcase names :param shallow_report: shallow report entry :return: generator yielding testcase reports and UIDs for merge step """ if testsuite_pattern == "*": yield {"runtime_status": RuntimeStatus.RUNNING}, [self.uid()] for testsuite_report in self._run_tests(): yield testsuite_report[self._TESTCASE_NAME], [ self.uid(), testsuite_report.uid, ] else: yield {"runtime_status": RuntimeStatus.RUNNING}, [ self.uid(), testsuite_pattern, ] testsuite_report = self._run_testsuite( self._pyunit_testcases[testsuite_pattern] ) yield testsuite_report[self._TESTCASE_NAME], [ self.uid(), testsuite_report.uid, ]
def _run_tests(self): """Run tests and yield testsuite reports.""" for pyunit_testcase in self.cfg.testcases: yield self._run_testsuite(pyunit_testcase) def _run_testsuite(self, pyunit_testcase): """Run a single PyUnit Testcase as a suite and return a testsuite report.""" suite = unittest.defaultTestLoader.loadTestsFromTestCase( pyunit_testcase ) suite_result = unittest.TextTestRunner().run(suite) # Since we can't reliably inspect the individual testcases of a PyUnit # suite, we put all results into a single "testcase" report. This # will only list failures and errors and not give detail on individual # assertions like with MultiTest. testcase_report = TestCaseReport( name=self._TESTCASE_NAME, uid=self._TESTCASE_NAME ) for call, error in suite_result.errors: assertion_obj = assertions.RawAssertion( description=str(call), content=str(error).strip(), passed=False ) testcase_report.append( schemas.base.registry.serialize(assertion_obj) ) for call, error in suite_result.failures: assertion_obj = assertions.RawAssertion( description=str(call), content=str(error).strip(), passed=False ) testcase_report.append( schemas.base.registry.serialize(assertion_obj) ) # In case of no failures or errors we need to explicitly mark the # testsuite as passed. if not testcase_report.entries: log_entry = entries_base.Log( "All PyUnit testcases passed", description="PyUnit success" ) testcase_report.append(schemas.base.registry.serialize(log_entry)) testcase_report.runtime_status = RuntimeStatus.FINISHED # We have to wrap the testcase report in a testsuite report. return TestGroupReport( name=pyunit_testcase.__name__, uid=pyunit_testcase.__name__, category=ReportCategories.TESTSUITE, entries=[testcase_report], )