How to run python unittests for multiple implementations in one go - python

I'm having trouble figuring out the proper way of using pythons unittest framework
I currently have 3 different implementations for a data structure class and unittests to test various things in the class as follows:
import fooHorse
import fooSnake
import fooMoose
import unittest
foo = fooHorse.foo()
#foo = fooSnake.foo()
#foo = fooMoose.foo()
class testFoo(unittest.TestCase):
def testSomething(self):
foo.do_something()
...
def testSomethingelse(self):
...
# etc
if __name__ == "__main__":
unittest.main()
How do I refactor the code so that all the tests are run for fooSnake.foo, fooMoose.foo and fooHorse.foo?

Just factor all the testing into a function and call it from the three tests :
class testFoo(unittest.TestCase):
def _doTest(self, foo):
foo.do_something()
# ...
def testFoorHorse(self):
foo = fooHorse.foo()
self._doTest(foo)
# and so on.
I wouldn't try to do anything more clever so that the test logic stays simple enought to be obviously bug-free.

I think it is better to keep the testing code inside the classes under test (so, inside the fooHorse classes and such). I can't really tell from the code segment, so maybe you are already doing that. Then to combine multiple tests to be run at the same time, or selecting a few of them, you could create a separate testing class that creates a test suite. In there, the individual unittests can be assigned. See the python docs for details on this.

Related

Basic testing system implementation

I've written a BaseTestCase class (which is meant to be inherited by all test cases) and a number of TestCase<Number>(BaseTestCase) classes (each in its own .py file).
The project structure is:
BaseTestCase.py
TestCase1.py
TestCase2.py
Example:
class TestCase2(BaseTestCase):
# methods
def execute(self):
self.method1()
self.method2()
self.method3()
The execute method should be called on an instance of TestCase<Number> to run a specific test. What is the proper way to run all test cases, i.e. to orchestrate them all?
I'm assuming you are using Unittest framework and want to run tests programmatically and have the ability to select which tests you run. If that's the correct assumption, here is the answer.
Lets assume you have those tests:
class TestExample1(unittest.TestCase):
def test_something(self):
pass
def test_something_else(self):
pass
class TestExample2(unittest.TestCase):
def test_something(self):
pass
def test_something_else(self):
pass
If those are in the same file, you can simply run them like this
# assuming your tests are above in this same file
unittest.main()
However, if they are in different files, you will have to extract the tests from them like so
for example in [TestExample1, TestExample2]:
tests = unittest.TestLoader().loadTestsFromTestCase(example)
unittest.TextTestRunner().run(tests)
This will result in two different executions like this
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
If you are considering other frameworks for running your tests, I recommend to take a look at Test Junkie: https://www.test-junkie.com/get-started/ as its much easier to get started with and is very powerful. (disclaimer: I'm the author!).

I have subclassed unittest.TestCase. Should I still be importing unittest every time I want to use #unittest.skipIf?

I have used python unittest quite a bit and there is a decorator method you can use to conditionally skip tests like this:
import unittest
class TestStringMethods(unittest.TestCase):
#unittest.skipIf(1 == 1, 'Skipped because 1 does indeed equal 1')
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
I wanted to add some features to the unittest.TestCase class though, so I subclassed it to start adding my own custom code:
import unittest
class CustomTestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # Just use whatever is in TestCase's init + our stuff
self.foo = 'foo' # our stuff
self.bar = 'bar'
def mymethod(self, param1, param2): # Some custom method I wanted to make for these custom test cases
pass
To continue using #unittest.skipIf I have been sticking import unittest at the top of any of my CustomTestCase test files, but I wonder if thats the correct way to be doing things. Am I importing more than I need? Or am I worried about nothing?
The fact that you've subclassed has little to do with what you're asking. In general, it's fine for subclasses to import or use their superclass: in fact, they must import their superclass when they're defined. It's the other way around that's the problem (superclass shouldn't know about its subclasses).
To continue using #unittest.skipIf I have been sticking import
unittest at the top of any of my CustomTestCase test files, but I
wonder if thats the correct way to be doing things. Am I importing
more than I need?
If you want to use any attribute off of the unittest module (including the skipIf decorator), then you have to import it into the module in question. It's no more complex than that.
If you're worried about something like header guards, like you need for C/C++ development, don't be. It doesn't work like the #include preprocessor directive (i.e. it's not actually including the source of the unittest module in your file).
If you're worried about importing unittest too many times, don't be. It's extremely common to import a module like unittest into many different modules of a given project.
Or am I worried about nothing?
Yes. Just import unittest whenever you need it and rid yourself of worry!
HTH.

Can I group test methods and/or test classes in Python unittest

Coming from PHPUnit, it was easy to group test classes or functions using the#group annotation. That way I could run or exclude a very particular subset of tests, potentially across multiple files.
I'm wondering if python unittest has something similar. If that is the case how do I use it and run it from the CLI?
Thanks.
It is possible to run a group of test functions by putting them all in a single class. Let's say you have 4 test functions in your unittest and you want to have two groups of 2 functions. You need to create a tests.py script with two classes, each of which having 2 functions:
from unittest import TestCase
class testClass1(TestCase):
def testFunction1(self):
#test something
def testFunction2(self):
#test something
class testClass2(TestCase):
def testFunction3(self):
#test something
def testFunction4(self):
#test something
Then to run your unittest only on class 1 from command line, you can run
python -m unittest tests.testClass1

Persist variable changes between tests in unittest?

How do I persist changes made within the same object inheriting from TestCase in unitttest?
from unittest import TestCase, main as unittest_main
class TestSimpleFoo(TestCase):
foo = 'bar'
def setUp(self):
pass
def test_a(self):
self.assertEqual(self.foo, 'bar')
self.foo = 'can'
def test_f(self):
self.assertEqual(self.foo, 'can')
if __name__ == '__main__':
unittest_main()
I.e.: I want those two tests above to pass
As some comments have echoed, structuring your tests in this manner is probably a design flaw in the tests themselves and you should consider restructuring them. However, if you want to do this and rely on the fact that the test runner you are using executes them in an alphabetical (seemingly) order then I suggest the following.
Similar to what #Matthias was saying but I would do one thing differently for the cases where you may decide to inherit from the class at a later date.
from unittest import TestCase, main as unittest_main
class TestSimpleFoo(TestCase):
foo = 'bar'
def setUp(self):
pass
def test_a(self):
self.assertEqual(self.__class__.foo, 'bar')
self.__class__.foo = 'can'
def test_f(self):
self.assertEqual(self.__class__.foo, 'can')
if __name__ == '__main__':
unittest_main()
The difference between this answer and #Matthias's answer you accepted is the explicit declaration of the class versus the lookup of said class reference.
TestSimpleFoo vs self.__class__
I prefer the dynamicness so I can inherit the tests later and run both test classes back to back and not have any cross over between the two. Because if you would choose to inherit from this class, explicitly naming the class reference would cause both test classes to run against that reference rather than their own respective classes.
I like your own answer for the simplicity of it, but if you want to keep distinct unit tests:
Apparently unittest runs separate tests with fresh instances of the TestCase. Well, just bind the objects to be persisted to something else but self. For example:
from unittest import TestCase, main as unittest_main
class TestSimpleFoo(TestCase):
def setUp(self):
pass
def test_a(self):
TestSimpleFoo.foo = 'can'
def test_f(self):
self.assertEqual(TestSimpleFoo.foo, 'can')
if __name__ == '__main__':
unittest_main()
You might be interesed in setUpClass and tearDownClass too:
https://docs.python.org/3/library/unittest.html#setupclass-and-teardownclass
Also take care about the execution order of your unit tests:
https://docs.python.org/2/library/unittest.html#unittest.TestLoader.sortTestMethodsUsing
Couldn't figure it out; so ended up hacking it out with multiple non test_ prefixed functions:
def test_password_credentials_grant(self):
for user in self.user_mocks:
self.register(user)
self.login(user)
self.access_token(user, self.assertEqual) # Ensures access_token is generated+valid
self.logout(user)
self.access_token(user, self.assertNotEqual) # Ensures access_token is now invalid
self.unregister(user)

python unittests with multiple setups?

I'm working on a module using sockets with hundreds of test cases. Which is nice. Except now I need to test all of the cases with and without socket.setdefaulttimeout( 60 )... Please don't tell me cut and paste all the tests and set/remove a default timeout in setup/teardown.
Honestly, I get that having each test case laid out on it's own is good practice, but i also don't like to repeat myself. This is really just testing in a different context not different tests.
i see that unittest supports module level setup/teardown fixtures, but it isn't obvious to me how to convert my one test module into testing itself twice with two different setups.
any help would be much appreciated.
you could do something like this:
class TestCommon(unittest.TestCase):
def method_one(self):
# code for your first test
pass
def method_two(self):
# code for your second test
pass
class TestWithSetupA(TestCommon):
def SetUp(self):
# setup for context A
do_setup_a_stuff()
def test_method_one(self):
self.method_one()
def test_method_two(self):
self.method_two()
class TestWithSetupB(TestCommon):
def SetUp(self):
# setup for context B
do_setup_b_stuff()
def test_method_one(self):
self.method_one()
def test_method_two(self):
self.method_two()
The other answers on this question are valid in as much as they make it possible to actually perform the tests under multiple environments, but in playing around with the options I think I like a more self contained approach. I'm using suites and results to organize and display results of tests. In order to run one tests with two environments rather than two tests I took this approach - create a TestSuite subclass.
class FixtureSuite(unittest.TestSuite):
def run(self, result, debug=False):
socket.setdefaulttimeout(30)
super().run(result, debug)
socket.setdefaulttimeout(None)
...
suite1 = unittest.TestSuite(testCases)
suite2 = FixtureSuite(testCases)
fullSuite = unittest.TestSuite([suite1,suite2])
unittest.TextTestRunner(verbosity=2).run(fullSuite)
I would do it like this:
Make all of your tests derive from your own TestCase class, let's call it SynapticTestCase.
In SynapticTestCase.setUp(), examine an environment variable to determine whether to set the socket timeout or not.
Run your entire test suite twice, once with the environment variable set one way, then again with it set the other way.
Write a small shell script to invoke the test suite both ways.
If your code does not call socket.setdefaulttimeout then you can run tests the following way:
import socket
socket.setdeaulttimeout(60)
old_setdefaulttimeout, socket.setdefaulttimeout = socket.setdefaulttimeout, None
unittest.main()
socket.setdefaulttimeout = old_setdefaulttimeout
It is a hack, but it can work
You could also inherit and rerun the original suite, but overwrite the whole setUp or a part of it:
class TestOriginal(TestCommon):
def SetUp(self):
# common setUp here
self.current_setUp()
def current_setUp(self):
# your first setUp
pass
def test_one(self):
# your test
pass
def test_two(self):
# another test
pass
class TestWithNewSetup(TestOriginal):
def current_setUp(self):
# overwrite your first current_setUp

Categories

Resources