2

I have a module which parses different file formats like CSV, XLS, HTML, etc.
The different formats contains exactly the same information, so I made different classes for parsing different file types. These classes have the exact same public API, and obviously have the same base class like this:

class BaseParser(object):
    def countTotalValues(self):
        pass

    def countItems(self):
        pass

class CSVParser(BaseParser):
    def __init__(self):
        """Init data, check for errors, etc.."""

    def parse(self):
        """ parses the data and set the result dictionaries like self.values, self.items, etc."""

class XLSParser(BaseParser):
    """ Ha exactly the same public API as CSVParser and set the same inner values. """
    pass

Is it a good idea to unit test each of the classes at once with the same values ? I have been doing this:

class TestParserClasses(unittest.TestCase):
    def setUp(self):
        self.instances = []
        for class_, file_ in PARSER_CLASSES:
            self.instances.append(class_(file_))

    def tearDown(self):
        del self.instances

and define every unit test this way:

    def test_count_total_values_without_parameter(self):
        for parser in self.instances:
            parser.parse()
            self.assertEqual(Decimal('9216.84'), parser.countTotalValues())

    def test_count_items_without_parameter(self):
        for parser in self.instances:
            parser.parse()
            self.assertEqual(128, parser.countItems())

Is it okay to do this? If yes, how to unit test all of them with the same TestCases at once without

    for parser in self.instances:
        parser.parse()

So I want to write unittest like this:

def test_count_total_values_without_parameter(self):
    self.assertEqual(Decimal('9216.84'), parser.countTotalValues())

def test_count_items_without_parameter(self):
    self.assertEqual(128, parser.countItems())

applied to every class. Is it possible ?

1

1 Answer 1

1

Have you considered creating a base TestCase and subclassing it for each of the classes you wish to test?

Create it like this, containing your actual test methods, and keep it in a separate module that does not match the test module pattern (by default, test*.py) so unittest won't discover it:

import unittest

class BaseTestCase(unittest.TestCase):
    def test_count_total_values_without_parameter(self):
        self.assertEqual(Decimal('9216.84'), self.parser.countTotalValues())

    # …more tests…

Now, in your test modules, do something like this:

import basetest

class TestCSVParser(basetest.BaseTestCase):
    def setUp(self):
        self.parser = CSVParser()

class TestXLSParser(basetest.BaseTestCase):
    def setUp(self):
        self.parser = XLSParser()
Sign up to request clarification or add additional context in comments.

8 Comments

This will run three tests: BaseTestCase.test_count..., TestCSVParser.test_count... and TestXLSParser.test_count..., because BaseTestCase will be autodetected as testcase in and of itself. The simple remedy is to write a mixin class with the test_count_... function and use multiple inheritance from both unittest.TestCase and baseTestCase.
@UlrichEckhardt That was why I kept BaseTestCase in a separate module. I created a simpler version of this to verify before making my post and python -m unittest discover did not pick up the basetest module; only the child testcases in the test module were picked up, since it matches the test*.py glob (see docs.python.org/2/library/unittest.html#test-discovery)
With @UlrichEckhardt's suggestion, this is great !
I updated the answer with @UlrichEckhardt 's suggestion and will accept it if you approve my edit.
@Walkman Thank you, but I would suggest going ahead and writing up your own answer with your preferred solution and accepting it. There are definitely multiple ways to do this one.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.