Unittest makes it easy to chain together test cases into a TestSuite. A TestSuite can be run just like a TestCase, but it also provides additional functionality to add a single test, multiple tests, and count them.
Why do we need this? Chaining together tests into a suite gives us the ability to pull together more than one module of test cases for a test run, as well as picking and choosing a subset of test cases. Up until now, we have generally run all the test methods from a single class. TestSuite gives us an alternative means to define a block of testing.
In the following steps, we will code multiple test case classes, and then load their test methods into suites so we can run them.
recipe5.py
in which to put our sample application and test cases.class RomanNumeralConverter(object): def __init__(self): self.digit_map = {"M":1000, "D":500, "C":100, "L":50, "X":10, "V":5, "I":1} def convert_to_decimal(self, roman_numeral): val = 0 for char in roman_numeral: val += self.digit_map[char] return val
import unittest class RomanNumeralConverterTest(unittest.TestCase): def setUp(self): self.cvt = RomanNumeralConverter() def test_parsing_millenia(self): self.assertEquals(1000, self.cvt.convert_to_decimal("M")) def test_parsing_century(self): self.assertEquals(100, self.cvt.convert_to_decimal("C")) class RomanNumeralComboTest(unittest.TestCase): def setUp(self): self.cvt = RomanNumeralConverter() def test_multi_millenia(self): self.assertEquals(4000, self.cvt.convert_to_decimal("MMMM")) def test_multi_add_up(self): self.assertEquals(2010, self.cvt.convert_to_decimal("MMX"))
recipe5_runner.py
that pulls in both test cases.if __name__ == "__main__": import unittest from recipe5 import * suite1 = unittest.TestLoader().loadTestsFromTestCase( RomanNumeralConverterTest) suite2 = unittest.TestLoader().loadTestsFromTestCase( RomanNumeralComboTest) suite = unittest.TestSuite([suite1, suite2]) unittest.TextTestRunner(verbosity=2).run(suite)
The unittest
module provides a convenient way to find all the test methods in a TestClass
and bundle them together as a suite using its loadTestsFromTestCase
. To further the usage of test suites, we are able to combine these two suites together as a single suite using unittest.TestSuite([list...])
. The TestSuite
class is designed to act like a TestCase
class, even though it doesn't subclass TestClass
, allowing us to run it using TextTestRunner
. This recipe shows the verbosity turned up, allowing us to see exactly which test methods were run, and which test case they came from.
In this recipe, we ran the tests from a different file from where the test cases are defined. This is different from the previous recipes where the runnable code and the test case were contained in the same file. Since the runner is defining the tests we run, we can easily create more runners that combine different suites of tests.
In the previous recipes, it has been advised to name the test case as [class under test]Test
. This is to make it apparent to the reader that the class under test and the related test share an important relationship. Now that we are introducing another test case, we need to pick a different name. The name should explain clearly why these particular test methods are split out into a separate class. For this recipe, the methods are split out to show more complex combinations of Roman numerals.
18.118.20.231