I was wondering when we run unittest.main()
, how does Python know what subclasses unittest.Testcase
has?
For example, if I add a class FromRomanBadInput(unittest.TestCase)
, how does unittest
know to run this?
So I looked around in my Python27/Lib
directory...
unittest.main
is actually an alias for a class, unittest.TestProgram
. So what happens is you construct an instance of this, and its __init__
runs, which does a bunch of sanity checks and configuration, including a dynamic import of the module that you called it from (it uses the __import__
function, with __main__
as the name of the module to import, by default). So now it has a self.module
attribute that contains a module object that represents your source.
Eventually, it gets to this code:
self.test = self.testLoader.loadTestsFromModule(self.module)
where self.testLoader
is an instance of unittest.TestLoader
. That method contains, among other stuff:
for name in dir(module): obj = getattr(module, name) if isinstance(obj, type) and issubclass(obj, case.TestCase): tests.append(self.loadTestsFromTestCase(obj))
So it uses the dir
of your module object to get the names of all the global variables you defined (including classes), filters that to just the classes that derive from unittest.TestCase
(locally, case.TestCase
is an alias for that), and then looks for test methods inside those classes to add to the tests
list. That search behaves similarly:
def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): return attrname.startswith(prefix) and \ hasattr(getattr(testCaseClass, attrname), '__call__') testFnNames = filter(isTestMethod, dir(testCaseClass))
so it uses the dir
of the class to get a list of names to try, looks for attributes with those names, and selects those that start with the self.testMethodPrefix
('test'
by default) and that are callable (have, in turn, a __call__
attribute). (I'm actually surprised they don't use the built-in callable
function here. I guess this is to avoid picking up nested classes.)
the 'main' function searches for all classes which inherits the unittest.TestCase in imported modules. and current path, then tries to run each method that starts with 'test'
from python's document:
import random import unittest class TestSequenceFunctions(unittest.TestCase): def setUp(self): self.seq = range(10) def test_shuffle(self): # make sure the shuffled sequence does not lose any elements random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, range(10)) # should raise an exception for an immutable sequence self.assertRaises(TypeError, random.shuffle, (1,2,3)) def test_choice(self): element = random.choice(self.seq) self.assertTrue(element in self.seq) def test_sample(self): with self.assertRaises(ValueError): random.sample(self.seq, 20) for element in random.sample(self.seq, 5): self.assertTrue(element in self.seq) if __name__ == '__main__': unittest.main()
A testcase is created by subclassing unittest.TestCase. The three individual tests are defined with methods whose names start with the letters test. This naming convention informs the test runner about which methods represent tests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With