Jonathan
Jonathan

Reputation: 11375

How to programmatically run Python unittest tests

I have the following tests from the unittest documentation.

import unittest

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # Check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

if __name__ == '__main__':
    unittest.main()

How do I run the above test from another Python program and be able to inspect the results and what tests have failed, if any?

Upvotes: 9

Views: 2773

Answers (1)

Adam Burke
Adam Burke

Reputation: 864

As mentioned in a comment by Patrick Haugh, and partially explained by the linked answer, the cleanest exposed API for this is unittest.main().

For example, this invokes the tests in the current module and then shows a basic way to interrogate the TestResult object in the result attribute.

import unittest

class APIUsageTest(unittest.TestCase):
    def test_success(self):
        None

    def test_fail(self):
        self.assertTrue(False)

def api_example():
    test = unittest.main(module=__name__,exit=False)
    print(f'Failures: {len(test.result.failures)}')
    print(f'Errors:   {len(test.result.errors)}')

if __name__ == '__main__':
    api_example()

Output:

$ python testapieg.py
F.
======================================================================
FAIL: test_fail (__main__.APIUsageTest.test_fail)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\adamb\bpm\statesnap-miner\testapieg.py", line 9, in test_fail
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
Failures: 1
Errors:   0

It is not all publicly documented, but the internal test classes in the unittest module can also be worked with directly. Eg, you could load the tests and invoke the test runner yourself.

import unittest

class APIUsageTest(unittest.TestCase):
    def test_success(self):
        None

    def test_fail(self):
        self.assertTrue(False)

def testrunner_example():
    tr = unittest.TextTestRunner()
    module = __import__(__name__)
    for part in __name__.split('.')[1:]:
        module = getattr(module, part)
    tests = unittest.defaultTestLoader.loadTestsFromModule( module )
    result = tr.run( tests )
    print(f'Failures: {len(result.failures)}')
    print(f'Errors:   {len(result.errors)}')

if __name__ == '__main__':
    testrunner_example()

(Same output as before).

If you go through the documentation and code, rich customisation of discovery, loading, and running is possible.

Upvotes: 0

Related Questions