Greetings, >Thank you very much Martin; you filled in a lot of details. I had an >overall understanding of what unittest does, but you have now enhanced >that understanding substantially.
Happy to help! I'll introduce you to my little menagerie below! >I'm still iffy on how the mixin class gets its test method called >when this class does not subclass from unittest.TestCase, but I >think I may have an idea now on how it is happening. Let's get to >that part of your response. Well, the mixin technique is not strictly speaking unittest related, but more a matter of understanding multiple inheritance. Once you understand that a bit better, I think you'll understand why this technique for using unittest works as it does. >> I'll make a few observations: >> >> - [on unittest] the unit testing tools use classes because it's a >> natural way to accommodate the goal of reproducibly setting up >> arguments and/or an environment for each test (note that each >> TestCase can have its own setUp() and tearDown() methods; this >> allows isolation) >> >> - [on unittest] each test collected by the TestLoader can be any >> Python class (as long as it is also derived from >> unittest.TestCase) I'll emphasize this point before going on further. All unittest.TestLoader cares about is that it has found (for example) an instance of something that is a unittest.TestCase. Your class can inherit from any number of other classes, but unittest.TestLoader will not find it, unless it also derives from unittest.TestCase. Now, on to the MRO bits. >> - [on your classes] your classes use a multiple inheritance >> model, deriving from TestFuncAcceptsSequencesMixin; when >> instantiated, they'll have all of the expected TestCase methods >> and the method called 'test_func' > >It is here that I am struggling. If the mixin class does not inherit >from unittest.TestCase, then how is test_func ever seen? Your classes (AcceptLists, AcceptTuples, AcceptStrings) specify both unittest.TestCase and TestFuncAcceptsSequencesMixin. This is multiple inheritance. (N.B. I'm not sure where to recommend further reading on MRO, but others on the list may know.) So, how is test_func ever seen? After your class is defined (and instantiated), the instance has access to all of the methods of all of the parent classes. In your case: * One of the parent classes of AcceptTuples is TestFuncAcceptsSequencesMixin which defines the method test_func. * The method 'test_func' matches the expectation of unittest when it goes looking for any method that matches the name 'test_*'. The number of methods on instances of unittest.TestCase class is higher (see at bottom of this email), but you will see your test_func method exists on each instance of the classes you created. >This answers one important thing I was wondering about: How do the >classes AcceptLists, AcceptStrings, and AcceptTuples get instantiated? >Apparently the unittest machinery does this for me. Yes. >> - for each method name starting with 'test_' (you have only >> 'test_func') TestRunner will: > >And here is my precise sticking point: How does the TestRunner >find test_func? The classes it has collected and instantiated >(AcceptLists, AcceptStrings and AcceptTuples) do not themselves >call and make use of the test_func method they inherit from the >mixin class. It looks for methods whose names match a specific pattern. The name should start with 'test_*' (this is configurable if you wanted your tests to begin with 'frobnitz_', but I haven't seen anybody do this). >> - execute the T.setUp() method if it exists >> >> - TestRunner will execute the method 'test_func' > >The only thing that makes sense to me is that the TestRunner >follows the MRO of the inherited classes and checks for any >test_xxx methods that might exist in those superclasses. Is this >correct or do I have a conceptual misunderstanding? No misunderstanding. All that's happening here is that unittest is defining your class (which imports / inherits everything it needs) and then is looking for the 'test_*' methods. You may (or may not) benefit from studying the MRO any further, but here's a function you could call to see multiple inheritance in action. Feed this function an instance of your class: def log_class_method_names(*args): import inspect for o in args: logging.info("Class %s found", o.__class__.__name__) for methodname, _ in inspect.getmembers(o, inspect.ismethod): logging.info("Class %s has method %s", o.__class__.__name__, methodname) If you try that with three instances of your classes, you should see all of the methods that unittest will see after the class is instantiated (see also at the foot of this email). See below my signature if you are a chimera aficianado, -Martin sample script to identify chimera features ------------------------------------------- import sys import unittest import logging logging.basicConfig(stream=sys.stderr, level=logging.INFO) logger = logging.getLogger() def log_class_method_names(*args): import pprint import inspect for o in args: logging.info("Class %s found", o.__class__.__name__) for methodname, _ in inspect.getmembers(o, inspect.ismethod): logging.info("Class %s has method %s", o.__class__.__name__, methodname) class Cat(object): def meow(self): return True class Snake(object): def hiss(self): return True class Plant(object): def wilt(self): return True class CatPlant(Cat, Plant): pass class SnakeCat(Snake, Cat): pass class PlantCatSnake(Plant, Cat, Snake): pass if __name__ == '__main__': # -- find the things that each of these normal critters can do # and then, the chimeras, too log_class_method_names(Cat(), Snake(), Plant(), CatPlant(), SnakeCat(), PlantCatSnake()) ------------- output of log_class_method_names(AcceptLists(), AcceptTuples(), AcceptStrings()) -------------------------------------------------------------------------------- INFO:root:Class AcceptLists found INFO:root:Class AcceptLists has method __call__ INFO:root:Class AcceptLists has method __eq__ INFO:root:Class AcceptLists has method __hash__ INFO:root:Class AcceptLists has method __init__ INFO:root:Class AcceptLists has method __repr__ INFO:root:Class AcceptLists has method __str__ INFO:root:Class AcceptLists has method _addExpectedFailure INFO:root:Class AcceptLists has method _addSkip INFO:root:Class AcceptLists has method _addUnexpectedSuccess INFO:root:Class AcceptLists has method _baseAssertEqual INFO:root:Class AcceptLists has method _deprecate INFO:root:Class AcceptLists has method _feedErrorsToResult INFO:root:Class AcceptLists has method _formatMessage INFO:root:Class AcceptLists has method _getAssertEqualityFunc INFO:root:Class AcceptLists has method _truncateMessage INFO:root:Class AcceptLists has method addCleanup INFO:root:Class AcceptLists has method addTypeEqualityFunc INFO:root:Class AcceptLists has method assertAlmostEqual INFO:root:Class AcceptLists has method assertAlmostEquals INFO:root:Class AcceptLists has method assertCountEqual INFO:root:Class AcceptLists has method assertDictContainsSubset INFO:root:Class AcceptLists has method assertDictEqual INFO:root:Class AcceptLists has method assertEqual INFO:root:Class AcceptLists has method assertEquals INFO:root:Class AcceptLists has method assertFalse INFO:root:Class AcceptLists has method assertGreater INFO:root:Class AcceptLists has method assertGreaterEqual INFO:root:Class AcceptLists has method assertIn INFO:root:Class AcceptLists has method assertIs INFO:root:Class AcceptLists has method assertIsInstance INFO:root:Class AcceptLists has method assertIsNone INFO:root:Class AcceptLists has method assertIsNot INFO:root:Class AcceptLists has method assertIsNotNone INFO:root:Class AcceptLists has method assertLess INFO:root:Class AcceptLists has method assertLessEqual INFO:root:Class AcceptLists has method assertListEqual INFO:root:Class AcceptLists has method assertLogs INFO:root:Class AcceptLists has method assertMultiLineEqual INFO:root:Class AcceptLists has method assertNotAlmostEqual INFO:root:Class AcceptLists has method assertNotAlmostEquals INFO:root:Class AcceptLists has method assertNotEqual INFO:root:Class AcceptLists has method assertNotEquals INFO:root:Class AcceptLists has method assertNotIn INFO:root:Class AcceptLists has method assertNotIsInstance INFO:root:Class AcceptLists has method assertNotRegex INFO:root:Class AcceptLists has method assertRaises INFO:root:Class AcceptLists has method assertRaisesRegex INFO:root:Class AcceptLists has method assertRaisesRegexp INFO:root:Class AcceptLists has method assertRegex INFO:root:Class AcceptLists has method assertRegexpMatches INFO:root:Class AcceptLists has method assertSequenceEqual INFO:root:Class AcceptLists has method assertSetEqual INFO:root:Class AcceptLists has method assertTrue INFO:root:Class AcceptLists has method assertTupleEqual INFO:root:Class AcceptLists has method assertWarns INFO:root:Class AcceptLists has method assertWarnsRegex INFO:root:Class AcceptLists has method assert_ INFO:root:Class AcceptLists has method countTestCases INFO:root:Class AcceptLists has method debug INFO:root:Class AcceptLists has method defaultTestResult INFO:root:Class AcceptLists has method doCleanups INFO:root:Class AcceptLists has method fail INFO:root:Class AcceptLists has method failIf INFO:root:Class AcceptLists has method failIfAlmostEqual INFO:root:Class AcceptLists has method failIfEqual INFO:root:Class AcceptLists has method failUnless INFO:root:Class AcceptLists has method failUnlessAlmostEqual INFO:root:Class AcceptLists has method failUnlessEqual INFO:root:Class AcceptLists has method failUnlessRaises INFO:root:Class AcceptLists has method func INFO:root:Class AcceptLists has method id INFO:root:Class AcceptLists has method run INFO:root:Class AcceptLists has method setUp INFO:root:Class AcceptLists has method setUpClass INFO:root:Class AcceptLists has method shortDescription INFO:root:Class AcceptLists has method skipTest INFO:root:Class AcceptLists has method subTest INFO:root:Class AcceptLists has method tearDown INFO:root:Class AcceptLists has method tearDownClass INFO:root:Class AcceptLists has method test_func INFO:root:Class AcceptTuples found INFO:root:Class AcceptTuples has method __call__ INFO:root:Class AcceptTuples has method __eq__ INFO:root:Class AcceptTuples has method __hash__ INFO:root:Class AcceptTuples has method __init__ INFO:root:Class AcceptTuples has method __repr__ INFO:root:Class AcceptTuples has method __str__ INFO:root:Class AcceptTuples has method _addExpectedFailure INFO:root:Class AcceptTuples has method _addSkip INFO:root:Class AcceptTuples has method _addUnexpectedSuccess INFO:root:Class AcceptTuples has method _baseAssertEqual INFO:root:Class AcceptTuples has method _deprecate INFO:root:Class AcceptTuples has method _feedErrorsToResult INFO:root:Class AcceptTuples has method _formatMessage INFO:root:Class AcceptTuples has method _getAssertEqualityFunc INFO:root:Class AcceptTuples has method _truncateMessage INFO:root:Class AcceptTuples has method addCleanup INFO:root:Class AcceptTuples has method addTypeEqualityFunc INFO:root:Class AcceptTuples has method assertAlmostEqual INFO:root:Class AcceptTuples has method assertAlmostEquals INFO:root:Class AcceptTuples has method assertCountEqual INFO:root:Class AcceptTuples has method assertDictContainsSubset INFO:root:Class AcceptTuples has method assertDictEqual INFO:root:Class AcceptTuples has method assertEqual INFO:root:Class AcceptTuples has method assertEquals INFO:root:Class AcceptTuples has method assertFalse INFO:root:Class AcceptTuples has method assertGreater INFO:root:Class AcceptTuples has method assertGreaterEqual INFO:root:Class AcceptTuples has method assertIn INFO:root:Class AcceptTuples has method assertIs INFO:root:Class AcceptTuples has method assertIsInstance INFO:root:Class AcceptTuples has method assertIsNone INFO:root:Class AcceptTuples has method assertIsNot INFO:root:Class AcceptTuples has method assertIsNotNone INFO:root:Class AcceptTuples has method assertLess INFO:root:Class AcceptTuples has method assertLessEqual INFO:root:Class AcceptTuples has method assertListEqual INFO:root:Class AcceptTuples has method assertLogs INFO:root:Class AcceptTuples has method assertMultiLineEqual INFO:root:Class AcceptTuples has method assertNotAlmostEqual INFO:root:Class AcceptTuples has method assertNotAlmostEquals INFO:root:Class AcceptTuples has method assertNotEqual INFO:root:Class AcceptTuples has method assertNotEquals INFO:root:Class AcceptTuples has method assertNotIn INFO:root:Class AcceptTuples has method assertNotIsInstance INFO:root:Class AcceptTuples has method assertNotRegex INFO:root:Class AcceptTuples has method assertRaises INFO:root:Class AcceptTuples has method assertRaisesRegex INFO:root:Class AcceptTuples has method assertRaisesRegexp INFO:root:Class AcceptTuples has method assertRegex INFO:root:Class AcceptTuples has method assertRegexpMatches INFO:root:Class AcceptTuples has method assertSequenceEqual INFO:root:Class AcceptTuples has method assertSetEqual INFO:root:Class AcceptTuples has method assertTrue INFO:root:Class AcceptTuples has method assertTupleEqual INFO:root:Class AcceptTuples has method assertWarns INFO:root:Class AcceptTuples has method assertWarnsRegex INFO:root:Class AcceptTuples has method assert_ INFO:root:Class AcceptTuples has method countTestCases INFO:root:Class AcceptTuples has method debug INFO:root:Class AcceptTuples has method defaultTestResult INFO:root:Class AcceptTuples has method doCleanups INFO:root:Class AcceptTuples has method fail INFO:root:Class AcceptTuples has method failIf INFO:root:Class AcceptTuples has method failIfAlmostEqual INFO:root:Class AcceptTuples has method failIfEqual INFO:root:Class AcceptTuples has method failUnless INFO:root:Class AcceptTuples has method failUnlessAlmostEqual INFO:root:Class AcceptTuples has method failUnlessEqual INFO:root:Class AcceptTuples has method failUnlessRaises INFO:root:Class AcceptTuples has method func INFO:root:Class AcceptTuples has method id INFO:root:Class AcceptTuples has method run INFO:root:Class AcceptTuples has method setUp INFO:root:Class AcceptTuples has method setUpClass INFO:root:Class AcceptTuples has method shortDescription INFO:root:Class AcceptTuples has method skipTest INFO:root:Class AcceptTuples has method subTest INFO:root:Class AcceptTuples has method tearDown INFO:root:Class AcceptTuples has method tearDownClass INFO:root:Class AcceptTuples has method test_func INFO:root:Class AcceptStrings found INFO:root:Class AcceptStrings has method __call__ INFO:root:Class AcceptStrings has method __eq__ INFO:root:Class AcceptStrings has method __hash__ INFO:root:Class AcceptStrings has method __init__ INFO:root:Class AcceptStrings has method __repr__ INFO:root:Class AcceptStrings has method __str__ INFO:root:Class AcceptStrings has method _addExpectedFailure INFO:root:Class AcceptStrings has method _addSkip INFO:root:Class AcceptStrings has method _addUnexpectedSuccess INFO:root:Class AcceptStrings has method _baseAssertEqual INFO:root:Class AcceptStrings has method _deprecate INFO:root:Class AcceptStrings has method _feedErrorsToResult INFO:root:Class AcceptStrings has method _formatMessage INFO:root:Class AcceptStrings has method _getAssertEqualityFunc INFO:root:Class AcceptStrings has method _truncateMessage INFO:root:Class AcceptStrings has method addCleanup INFO:root:Class AcceptStrings has method addTypeEqualityFunc INFO:root:Class AcceptStrings has method assertAlmostEqual INFO:root:Class AcceptStrings has method assertAlmostEquals INFO:root:Class AcceptStrings has method assertCountEqual INFO:root:Class AcceptStrings has method assertDictContainsSubset INFO:root:Class AcceptStrings has method assertDictEqual INFO:root:Class AcceptStrings has method assertEqual INFO:root:Class AcceptStrings has method assertEquals INFO:root:Class AcceptStrings has method assertFalse INFO:root:Class AcceptStrings has method assertGreater INFO:root:Class AcceptStrings has method assertGreaterEqual INFO:root:Class AcceptStrings has method assertIn INFO:root:Class AcceptStrings has method assertIs INFO:root:Class AcceptStrings has method assertIsInstance INFO:root:Class AcceptStrings has method assertIsNone INFO:root:Class AcceptStrings has method assertIsNot INFO:root:Class AcceptStrings has method assertIsNotNone INFO:root:Class AcceptStrings has method assertLess INFO:root:Class AcceptStrings has method assertLessEqual INFO:root:Class AcceptStrings has method assertListEqual INFO:root:Class AcceptStrings has method assertLogs INFO:root:Class AcceptStrings has method assertMultiLineEqual INFO:root:Class AcceptStrings has method assertNotAlmostEqual INFO:root:Class AcceptStrings has method assertNotAlmostEquals INFO:root:Class AcceptStrings has method assertNotEqual INFO:root:Class AcceptStrings has method assertNotEquals INFO:root:Class AcceptStrings has method assertNotIn INFO:root:Class AcceptStrings has method assertNotIsInstance INFO:root:Class AcceptStrings has method assertNotRegex INFO:root:Class AcceptStrings has method assertRaises INFO:root:Class AcceptStrings has method assertRaisesRegex INFO:root:Class AcceptStrings has method assertRaisesRegexp INFO:root:Class AcceptStrings has method assertRegex INFO:root:Class AcceptStrings has method assertRegexpMatches INFO:root:Class AcceptStrings has method assertSequenceEqual INFO:root:Class AcceptStrings has method assertSetEqual INFO:root:Class AcceptStrings has method assertTrue INFO:root:Class AcceptStrings has method assertTupleEqual INFO:root:Class AcceptStrings has method assertWarns INFO:root:Class AcceptStrings has method assertWarnsRegex INFO:root:Class AcceptStrings has method assert_ INFO:root:Class AcceptStrings has method countTestCases INFO:root:Class AcceptStrings has method debug INFO:root:Class AcceptStrings has method defaultTestResult INFO:root:Class AcceptStrings has method doCleanups INFO:root:Class AcceptStrings has method fail INFO:root:Class AcceptStrings has method failIf INFO:root:Class AcceptStrings has method failIfAlmostEqual INFO:root:Class AcceptStrings has method failIfEqual INFO:root:Class AcceptStrings has method failUnless INFO:root:Class AcceptStrings has method failUnlessAlmostEqual INFO:root:Class AcceptStrings has method failUnlessEqual INFO:root:Class AcceptStrings has method failUnlessRaises INFO:root:Class AcceptStrings has method func INFO:root:Class AcceptStrings has method id INFO:root:Class AcceptStrings has method run INFO:root:Class AcceptStrings has method setUp INFO:root:Class AcceptStrings has method setUpClass INFO:root:Class AcceptStrings has method shortDescription INFO:root:Class AcceptStrings has method skipTest INFO:root:Class AcceptStrings has method subTest INFO:root:Class AcceptStrings has method tearDown INFO:root:Class AcceptStrings has method tearDownClass INFO:root:Class AcceptStrings has method test_func -- Martin A. Brown http://linux-ip.net/ _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor