Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python unittest multiple mixins

I'm trying to write a way of testing some XML files. The XML files describe input into a scientific analysis program where various parameters can be defined. I want to write unittests for my XML files so I know that the program is configured correctly.

I'm currently doing this as a library with a base test class containing various tests and some mixins for subcomponents. But the subcomponents are repeated a number of times so I want the tests to run once for each mixin e.g.:

class BaseTest(object):
    xmlfile = '...'
    ...

class ComponentMixin(object):
    xmlid = None   # 
    var = None     # 

    def test_var(self):
        assert self.var == "whatever_the_value_is_in self.xmlfile"
    # ... and a number of other tests and variables.

... now for each analysis there can be a number of components defined with different parameters. I'm hoping to do something like this --

 class MyFirstComponentMixin(ComponentMixin):
      xmlid = 'component1'
      var = 'one'

 class MySecondComponentMixin(ComponentMixin):
      xmlid = 'component2'
      var = 'two'

 class MyTest(BaseTest, MyFirstComponentMixin, MySecondComponentMixin, unittest.TestCase):
      xmlfile = '...'

... but the problem is that test_var will only be called for component2 and not component2. Is there a way around this, or a better solution?

like image 214
Puzzled79 Avatar asked Oct 31 '22 23:10

Puzzled79


1 Answers

As you were advised in comment: composition is better solution for your problem than inheritance. The idea is to define multiple standalone TestCases (parts) for pieces of the XML file and then compose them into single TestSuite (composite).

Library

It is a base class for part.

class BaseTestCase(unittest.TestCase):
    xmlfile = None  # will be set by containing test suite

It is an abstract component test case implementation.

class ComponentTestCase(BaseTestCase):
    xmlid = None
    var = None

    def test_var(self):
        assert self.var == "whatever_the_value_is_in self.xmlfile"

It is a base for our composite. It defines convenient copying of the xmlfile from composite to its parts.

class BaseTestSuite(unittest.TestSuite):
    xmlfile = None

    def addTest(self, test):
        if isinstance(test, BaseTestCase):
            test.xmlfile = self.xmlfile

        super(BaseTestSuite, self).addTest(test)

Usage

It is specific part, which tests some specific aspect of the XML:

class MySpecificTestCase(BaseTestCase):
    def test_something_specific(self):
        self.assertEqual(4, 2 + 2)

These are parts, which test particular components:

class MyFirstComponentTestCase(ComponentTestCase):
    xmlid = 'component1'
    var = 'one'


class MySecondComponentTestCase(ComponentTestCase):
    xmlid = 'component2'
    var = 'two'

Here is a composite with XML you want to test.

class MyTest(BaseTestSuite):
    xmlfile = '<some_xml></some_xml>'

We define load_tests to return TestSuite with all TestCases included.

def load_tests(loader, standard_tests, pattern):
    return MyTest((
        loader.loadTestsFromTestCase(MySpecificTestCase),
        loader.loadTestsFromTestCase(MyFirstComponentTestCase),
        loader.loadTestsFromTestCase(MySecondComponentTestCase)
    ))

This approach has one limitation: you can't test few XML files from the single Python file. Basically you can, but output won't help you to identify, which XML file is broken.


Your case is a bit tricky. unittest were designed to test code, not data. Maybe validation against XML schema is what you need.

like image 136
Yaroslav Admin Avatar answered Nov 08 '22 05:11

Yaroslav Admin