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

Reply via email to