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):
...
Related
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
So, I have fixtures defined in conftest.py file with scope="class" as I want to run them before each test class is invoked. The conftest file is placed inside project root directory for it to be visible to every test module.
Now in one of the test modules, I have another setup function which I want to run once for that module only. But the problem is setup_class() method is called before running fixtures defined in conftest.py. Is this expected? I wanted it to be opposite because I want to use something done in the fixtures defined in conftest. How to do that?
Code -
conftest.py:
#pytest.fixture(scope="class")
def fixture1(request):
#set a
#pytest.fixture(scope="class")
def fixture1(request):
test_1.py:
#pytest.mark.usefixtures("fixture_1", "fixture_2")
class Test1():
#need this to run AFTER the fixture_1 & fixture_2
def setup_class():
#setup
#get a set in fixture_1
def test_1()
.....
I know that I could simply define a fixture in the test file instead of setup_class but then I will have to specify it in arguments of every test method in order it to be invoked by pytest. But suggestions are welcome!
I have exactly the same problem. Only now I have realized that the problem might be taht the setup_class is called before the fixture >-/
I think that this question is similar to this one
Pytest - How to pass an argument to setup_class?
And the problem is mixing the unittest and pytest methods.
I kind of did what they suggested - I ommitted the setup_class and created a new fixture within the particular test file,
calling the fixture in the conftest.py.
It works so far.
M.
The problem is that you can use the result of a fixture only in test function (or method) which is run by pytest. Here I can suggest a workaround. But of course I'm not sure if it suites your needs.
The workaround is to call the function from a test method:
conftest.py
#pytest.fixture(scope='class')
def fixture1():
yield 'MYTEXT'
test_1.py
class Test1:
def setup_class(self, some_var):
print(some_var)
def test_one(self, fixture1):
self.setup_class(fixture1)
Fixtures and setup_class are two different paradigms to initialize test functions (and classes). In this case, mixing the two creates a problem: The class-scoped fixtures run when the individual test functions (methods) run. On the other hand, setup_class runs before they do. Hence, it is not possible to access a fixture value (or fixture-modified state) from setup_class.
One of the solutions is to stop using setup_class entirely and stick with a fixtures-only solution which is the preferred way in pytest nowadays (see the note at the beginning).
# conftest.py or the test file:
#pytest.fixture(scope="class")
def fixture_1(request):
print('fixture_1')
# the test file:
class Test1():
#pytest.fixture(scope="class", autouse=True)
def setup(self, fixture_1, request):
print('Test1.setup')
def test_a(self):
print('Test1.test_a')
def test_b(self):
print('Test1.test_b')
Note that the setup fixture depends on fixture_1 and hence can access it.
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.
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.
I am trying to create test classes that aren't unittest based.
This method under this class
class ClassUnderTestTests:
def test_something(self):
cannot be detected and run when you call py.test from the command line or when you run this test in PyCharm (it's on its own module).
This
def test_something(self):
same method outside of a class can be detected and run.
I'd like to group my tests under classes and unless I'm missing something I'm following the py.test spec to do that.
Environment: Windows 7, PyCharm with py.test set as the test runner.
By convention it searches for
Test prefixed test classes (without an init method)
eg.
# content of test_class.py
class TestClass:
def test_one(self):
x = "this"
assert 'h' in x
def test_two(self):
x = "hello"
assert hasattr(x, 'check')
# this works too
#staticmethod
def test_three():
pass
# this doesn't work
##classmethod
#def test_three(cls):
# pass
See the docs:
Group multiple tests in a class
Conventions for Python test discovery
The accepted answer is not incorrect, but it is incomplete. Also, the link it contains to the documentation no longer works, nor does the updated link in the a comment on that answer.
The current documentation can now be found here. The relevant bits of that doc are:
...
In those directories, search for test_*.py or *_test.py files, imported by their test package name.
From those files, collect test items:
...
test prefixed test functions or methods inside Test prefixed test classes (without an __init__ method)
The key bit that is missing in the accepted answer is that not only must the class name start with Test and not have an __init__ method, but also, the name of the file containing the class MUST be of one of the forms test_*.py or *_test.py.
Where I got tripped up here, and I assume many others will too, is that I generally name my Python source files containing only a class definition to directly mirror the name of the class. So if my class is named MyClass, I normally put its code in a file named MyClass.py. I then put test code for my class in a file named TestMyClass.py. This won't work with PyTest. To let PyTest do its thing with my test class, I need to name the file for this class test_MyClass.py or MyClass_test.py. I chose the last form so that I generally add a '_test' suffix to the file names I'd otherwise choose that need to be named so that PyTest will parse them looking for tests.