开发者

Giving parameters into TestCase from Suite in python

From python documentation(http://docs.python.org/library/unittest.html):

开发者_如何学编程
import unittest

class WidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget('The widget')

    def tearDown(self):
        self.widget.dispose()
        self.widget = None

    def test_default_size(self):
        self.assertEqual(self.widget.size(), (50,50),
                         'incorrect default size')

    def test_resize(self):
        self.widget.resize(100,150)
        self.assertEqual(self.widget.size(), (100,150),
                         'wrong size after resize')

Here is, how invoke those testcase:

def suite():
    suite = unittest.TestSuite()
    suite.addTest(WidgetTestCase('test_default_size'))
    suite.addTest(WidgetTestCase('test_resize'))
    return suite

Is it possible to insert parameter custom_parameter into WidgetTestCase like:

class WidgetTestCase(unittest.TestCase):
    def setUp(self,custom_parameter):
        self.widget = Widget('The widget')
        self.custom_parameter=custom_parameter

?


What I've done is in test_suite module just added

WidgetTestCase.CustomParameter="some_address"

The simplest solutions are the best :)


I've found a way to do this, but it's a bit of a cludge.

Basically, what I do is add, to the TestCase, an __init__ method which defines a 'default' parameter and a __str__ so that we can distinguish cases:

class WidgetTestCase(unittest.TestCase):

    def __init__(self, methodName='runTest'):
        self.parameter = default_parameter
        unittest.TestCase.__init__(self, methodName)

    def __str__(self):
        ''' Override this so that we know which instance it is '''
        return "%s(%s) (%s)" % (self._testMethodName, self.currentTest, unittest._strclass(self.__class__))

Then in suite(), I iterate over my test parameters, replacing the default parameter with one specific to each test:

def suite():
    suite = unittest.TestSuite()

    for test_parameter in test_parameters:
        loadedtests = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
        for t in loadedtests:
            t.parameter = test_parameter
        suite.addTests(loadedtests)

    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(OtherWidgetTestCases))
    return suite

where OtherWidgetTestCases are tests which don't need to be parameterised.

For instance I have a bunch of tests on real data for which a suite of tests need to be applied to each, but I also have some synthetic data sets, designed to test certain edge cases not normally present in the data, and I only need to apply certain tests to those, so they get their own tests in OtherWidgetTestCases.


This is something that has been on my mind recently. Yes it is very possible to do. I called it scenario testing, but I think parameterized may be more accurate. I put a proof of concept up as a gist here. In short it is a meta class that allows you to define a scenario and run the tests against it a bunch. With it your example can be something like this:

class WidgetTestCase(unittest.TestCase):
    __metaclass__ = ScenarioMeta
    class widget_width(ScenerioTest):
        scenarios = [
            dict(widget_in=Widget("One Way"), expected_tuple=(50, 50)),
            dict(widget_in=Widget("Another Way"), expected_tuple=(100, 150))
        ]
        def __test__(self, widget_in, expected_tuple):
            self.assertEqual(widget_in.size, expected_tuple)

When run, the meta class writes 2 seperate tests out so the output would be something like:

$ python myscerariotest.py -v
test_widget_width_0 (__main__.widget_width) ... ok
test_widget_width_1 (__main__.widget_width) ... ok


----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

As you can see the scenarios are converted to tests at runtime.

Now I am not yet sure if this is even a good idea. I use it in tests where I have a lot of text centric cases that repeat the same assertions on slightly different data, which helps me to catch the little edge cases. But the classes in that gist do work and I believe it accomplishes what you are after.

Note that the with some trickery the test cases can be given names and even pulled from an external source like a text file or database. Its not documented yet but some digging around in the meta class should get you started. There is also some more info and examples on my post here.

Edit

This is an ugly hack that I do not support anymore. The implementation should have been done as a subclass of TestCase, not as a hacked meta class. Live and learn. An even better solution would be to use nose generators.


I don't believe so, the signature for setUp needs to be what unittest is expecting, afaik, setUp is automagically called within the testcase's run method as setUp()... you're not going to be able to pass it unless you override run to pass in the var you want. But I think what you want defeats the purpose of unit testing. Don't try to use a DRY philosophy with this, each unit you're testing should be a part of a class or even part of a function/method.


I don't think this is a good idea. Unit tests should be thorough enough that you test all functionality in your cases so passing in different parameteres shouldn't be required.

You mention you're passing in a www address - this is almost certainly not a good idea. What happens if you try and run the tests on a machine where the 'net connection is down? Your tests should be:

  • Automatic - they will run on all machines and platforms where your app is supported, without user intervention. They shouldn't rely on external environment to pass. This means (amongst other things) that relying on a properly set up connection to the Internet is a bad idea. You can get around this by providing dummy data. Instead of passing in a URL to a resource, abstract away the data source and pass in a data-stream or whatever. This is especially easy in python since you can make use of python's duck-typing to present a stream-like object (python frequently uses a "file-like" object for this very reason!).

  • Thorough - your unit tests should have 100% code coverage, and cover all possible situations. You want to test your code with multiple sites? Instead, test your code with all the possible features that a site may include. Without knowing more about what your application does, I can't offer much advice in this point.

Now, it looks like you're tests are going to be heavily data-driven. There are many tools that allow you to define data-sets for unit tests and load them in the tests. Check out python test fixtures, for example.

I realise that this isn't the answer you're looking for, but I think you'll have more joy in the long-run if you follow these principles.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜