Python Unittest structure - python

So in my project I have a long (~1000 lines)TestCase module with only 1 TestCase.
I want to divide it into 3-4 separate TestCase modules (separate files).
But how can I make a common setUp to share fixtures for all modules?
Use some import fixtures?
I use setUpClass in that my long module with a single TestCase.
Pls, advise.

What you can do is define a parent class, e.g.
class CommonTestCase(unittest.TestCase):
def setUpClass(self):
# Do setup or anything else here
and then in other files or cases you can use inheritance to use the same setup steps from parent class CommonTestCase:
from my_package import CommonTestCase
class MyTestCaseA(CommonTestCase):
def test_this(self):
# Test implementation
class MyTestCaseB(CommonTestCase):
def test_that(self):
# Test implementation

Related

How to use unittest setUp method only once to set attributes used in test submodules?

I would like to have a unittest Class that instantiate a Class once and sets this instance in an attribute that can be reusable in tests submodules (NOT other tests in this file).
e.g:
\tests
test_main.py
\subtests_1
test_1.py
\subtests_2
test_2.py
In the test_main.py:
class TestMain(unittest.TestCase):
def setUp(self):
config = Config('test')
In the test_1.py and test_2.py I want to access this attribute without (re)instantiating my config.
class TestHello(unittest.TestCase):
def SetUp(self):
my_object = MyObject(self.config)
The reason why is because all classes that I want to test needs to be instantiated be this config so I would like to avoid redundancy.
I tested it in the init.py or in the test_main.py file and I'm sure that unittest pass through this method but I can't access it in submodules even with the setUpClass method. Maybe I don't access it in a right way.
I tried accessing it with
self.__class__.config
self.config
Each time I have the error:
AttributeError: type object 'TestHello' has no attribute 'config'
Any advise would be very helpful !
Tests are expected to be independant and you should never rely on one installing something for a different one. But Python unittest module provide 3 setUp (and tearDown) levels:
the normal test level: the setUp (and tearDown) methods are called for each test method.
the class level: the classmethods setUpClass and tearDownClass are called only once for the whole class before (and after) all test methods of the class are executed.
the module level: a test module can also contain the free functions setUpModule and tearDownModule. They are called (resp.) before any test in the module and after all have been executed.
They can be used to perform only once expensive initialization, or initialize objects that have to be shared among several tests.

Tests being run from imported class

I have a base class with some tests similar to this:
class TestA:
def test_something(self):
data = self._generate_some_data()
assert something_about_data
def _generate_some_data(self)
return some_data
And another class that reuses the testing logic within TestA but providing different data:
# This is the line that is giving me a problem
from somemodule import TestA
class TestB(TestA):
def _generate_some_data(self)
return some_other_data
Note that I am doing this and not simply creating another test in TestA because they each test a different class A and B (though the classes have the same interface)
The problem I am running into is, when importing TestA in the TestB module, the name is declared in the module's namespace and therefore its found by pytest when searching for tests.
This results in TestA tests being run twice: one when its module is found and scanned, and another time when TestB module is scanned.
I have thought of two solutions:
A simple work around: renaming TestA upon import so that it is not found by pytest scanning:
from somemodule import TestA as BaseTestA
class TestB(BaseTestA):
...
I could extract the common logic to an abstract class whose name will not match pytest search, and that could be safely imported and inherited from by both test classes.
The first option, I do not like it, as it seems hacky. And regarding the second option, I would not really want to extract the logic to another class.
Is there another way to solve this problem that I am not seeing?
Just use:
import somemodule
class TestB(somemodule.TestA):
...

Using Class inheritance while designing test suite

I have a requirement to implement a test suite for multiple functions.
I am trying to figure out best practices to leverage existing pytest design pattern.
There are 2-3 common test cases for all the functions
Each function require different presetup condition
My current design :
/utils
logic.py
/tests
Test_Regression.py
Sedan/
Test_Sedan.py
SUV/
Test_SUV.py
Hatchback/
Test_Hatchback.py
/config
Configuration.py
Current folder structure
Regression.py : This class holds common testcases
Test_SUV.py : This class inherits Test_Regression class test cases and has SUV specific test cases
Utils : This folder stores the program logic
is this a good design practice for a test suite to have class inheritance
class Regression:
#pytest.parameterize(x, utils.logic_func())
#pytest.mark.testengine
def test_engine(x,self):
#validates logic
assert x == 0
#pytest.parameterize(y, utils.logic_func())
#pytest.mark.testheadlight
def test_headlight(y,self):
#validates logic
assert y == 0
class Test_SUV(Test_Regression):
def get_engine_values():
# calls program logic
return x
.
.
.
.
Or is there a better way to structure these test cases.
Preconditions function can be annotated with #pytest.fixture and that can be used as parameter to the test methods instead of utility functions. You can define the scope (function, class, module, package or session) of these fixture functions: More details about fixture: https://docs.pytest.org/en/6.2.x/fixture.html
Pytest over unittest - one reason is you can avoid implicit class requirement and keep your tests simple and less verbose. And if you are adding class for pytest, then we are losing this benefit. IMHO, you can keep your common tests in regression module and avoid Regression class and Test Class inheritance, because this is going to be hard to maintain in long run.
Your tests should be independent from each other. If there is a common functionality that you want to share or inherit, you can do that via fixtures and keep them in a module called conftest.py and all those functions in conftest.py will then be available to all modules in the package and sub-packages More details about conftest

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.

How to run the same unittest suite with several backends

I have a JSON parser library (ijson) with a test suite using unittest. The library actually has several parsing implementations — "backends" — in the form of a modules with the identical API. I want to automatically run the test suite several times for each available backend. My goals are:
I want to keep all tests in one place as they are backend agnostic.
I want the name of the currently used backend to be visible in some fashion when a test fails.
I want to be able to run a single TestCase or a single test, as unittest normally allows.
So what's the best way to organize the test suite for this? Write a custom test runner? Let TestCases load backends themselves? Imperatively generate separate TestCase classes for each backend?
By the way, I'm not married to unittest library in particular and I'm open to try another one if it solves the problem. But unittest is preferable since I already have the test code in place.
One common way is to group all your tests together in one class with an abstract method that creates an instance of the backend (if you need to create multiple instances in a test), or expects setUp to create an instance of the backend.
You can then create subclasses that create the different backends as needed.
If you are using a test loader that automatically detects TestCase subclasses, you'll probably need to make one change: don't make the common base class a subclass of TestCase: instead treat it as a mixin, and make the backend classes subclass from both TestCase and the mixin.
For example:
class BackendTests:
def make_backend(self):
raise NotImplementedError
def test_one(self):
backend = self.make_backend()
# perform a test on the backend
class FooBackendTests(unittest.TestCase, BackendTests):
def make_backend(self):
# Create an instance of the "foo" backend:
return foo_backend
class BarBackendTests(unittest.TestCase, BackendTests):
def make_backend(self):
# Create an instance of the "bar" backend:
return bar_backend
When building a test suite from the above, you will have independent test cases FooBackendTests.test_one and BarBackendTests.test_one that test the same feature on the two backends.
I took James Henstridge's idea with a mixin class holding all the tests but actual test cases are then generated imperatively, as backends may fail on import in which case we don't want to test them:
class BackendTests(object):
def test_something(self):
# using self.backend
# Generating real TestCase classes for each importable backend
for name in ['backend1', 'backend2', 'backend3']:
try:
classname = '%sTest' % name.capitalize()
locals()[classname] = type(
classname,
(unittest.TestCase, BackendTests),
{'backend': import_module('backends.%s' % name)},
)
except ImportError:
pass

Categories

Resources