I really couldn't find a solution for :
PytestCollectionWarning: cannot collect test class 'TestBlaBla' because it has a init constructor
Here is my testing module and it needs to take the arguments outside of this file because at the end of the day I'm gonna call all test modules in a single file and run them all over different names and there is a bunch of names. I have to init them but when I run pytest it always ignores these classes. Idk how to handle without initializing them. If there is any suggestions I would be glad to hear.
tests/test_bla_bla.py
class TestBlaBla():
def __init__(self, **kwargs):
self.name1 = kwargs.get("name1")
self.name2 = kwargs.get("name2")
#pytest.fixture(scope='session')
def load_data_here(self):
return load_data(self.name1) # a function comes from a utils file. it only stands for load data and it needs take a name for path
..
"continue with test_ functions that use output of load_data_here"
tests/main.py
class TestingAll:
def __init__(self, *args, **kwargs):
self.name1 = kwargs.get("name1")
self.name2 = kwargs.get("name2")
self._process()
def _process(self):
TestBlaBla(name1 = self.name1, name2= self.name2)
TestBlaBla2(name1 = self.name1, name2= self.name2)
if __name__ == "__main__":
Test = TestingAll(name1 = "name1", name2= "name2")
Python test modules cannot have init methods as python test instantiates the class itself and there is not any way (IMHO?) to extend the instantiation and add arguments.
Yes, it is a natural idea to want to make your tests flexible by passing in command-line arguments. But you can't :-P. So you need to find another way of doing this.
Note also the if name == 'main': can work if you call the test file with python and add some code to explicitly call a py test runner. Note you do not just call your test class. A python test runner needs to be instantiated itself and run tests in a particular way.
e.g. we can have this which will allow python to instantiate and run tests in a TestingAll class (as long as it doesn't have an init method).
This uses the unittest.TextTestRunner
Note there are all sorts of python test runners, also runners like nose2 or like py.test which use a different test library.
if __name__ == '__main__':
unittest.main()
suite = unittest.TestLoader().loadTestsFromTestCase(TestingAll)
unittest.TextTestRunner(verbosity=3).run(suite)
You could maybe have an ArgsProcess class to process command line args.
Then iterate and set a global var with each value to be used and call the test runner each time.
But it depends on how your tests will be used.
The answers on this question already mentioned in comments explain and link to documentation for this warning:
py.test skips test class if constructor is defined
The answer on this question shows how an init method is replaced by using fixture:
Pytest collection warning due to __init__ constructor
Maybe something like this would work for you.
Related
I have following unittest code running via py.test.
Mere presence of the constructor make the entire class skip when running
py.test -v -s
collected 0 items / 1 skipped
Can anyone please explain to me this behaviour of py.test?
I am interested in understanding py.test behaviour, I know the constructor is not needed.
Thanks,
Zdenek
class TestClassName(object):
def __init__(self):
pass
def setup_method(self, method):
print "setup_method called"
def teardown_method(self, method):
print "teardown_method called"
def test_a(self):
print "test_a called"
assert 1 == 1
def test_b(self):
print "test_b called"
assert 1 == 1
The documentation for py.test says that py.test implements the following standard test discovery:
collection starts from the initial command line arguments which may be directories, filenames or test ids.
recurse into directories, unless they match norecursedirs
test_*.py or *_test.py files, imported by their package name.
Test prefixed test classes (without an __init__ method) [<-- notice this one here]
test_ prefixed test functions or methods are test items
So it's not that the constructor isn't needed, py.test just ignores classes that have a constructor. There is also a guide for changing the standard test discovery.
As already mentioned in the answer by Matti Lyra py.test purposely skips classes which have a constructor. The reason for this is that classes are only used for structural reasons in py.test and do not have any inherent behaviour, while when actually writing code it is the opposite and much rarer to not have an .__init__() method for a class. So in practice skipping a class with a constructor will likely be what was desired, usually it is just a class which happens to have a conflicting name.
Lastly py.test needs to instantiate the class in order to execute the tests. If the constructor takes any arguments it can't instantiate it, so again skipping is the right thing to do.
All the above answers clearly explain the underlying cause, I just thought to share my experience and workaround the warnings.
I got my test to work without the warnings by aliasing the imported Class
from app.core.utils import model_from_meta
from app.core.models import Panel, TestType as _TestType
from app.core.serializers import PanelSerializer, TestType as _TestTypeSerializer
def test_model_from_meta():
assert (Panel is model_from_meta(PanelSerializer))
assert (_TestType is model_from_meta(_TestTypeSerializer))
After importing the class using aliases the warnings no longer get printed
I hope this helps someone.
In my case, I just so happened to have a parameter's class names TestParams, which conflicts with pytest looking for classes beginning with the name test....
Solution: rename your own class
Source
I started using python's Nose to execute my functional tests.
I use it with SauceLab's service. I execute the tests from the command line and see the reports on Sauce dashboard.
Now, every test is a class containing setUp() , the_test() , and tearDown() methods.
Inside the setUp() method there are the capabilities passed to Sauce configuring the Browser/version/OS the test will run on.
def setUp(self):
#REMOTE
desired_capabilities = webdriver.DesiredCapabilities.FIREFOX
desired_capabilities['version'] = '21'
desired_capabilities['platform'] = 'Windows XP'
desired_capabilities['name'] = className.getName(self)
desired_capabilities['record-video'] = False
self.wd = webdriver.Remote(desired_capabilities=desired_capabilities,command_executor="http://the_username:the_API_key#ondemand.saucelabs.com:80/wd/hub")
self.wd.implicitly_wait(10)
I would like to do the following...:
Create a separate file containing the setUp and tearDown functions and just call them by name every time exactly where i need them(before and after the test/tests).
Now they exist inside each and every python file I have and they are the same piece of code.
Additionally I think there is a way that nose provides to automatically see the two functions and call them when is needed. Is it feasible?
Thank you in advance
Put them in a super class.
def MyTestCase(TestCase):
def setUp(self):
# do setup stuff
Then each of your tests can inherit from MyTestCase. You can then further over ride setUp or tearDown in each test class. But do remember to call the super classes init method as well.
How do I create a single setup function all my nose test cases that is only called once during initialization? I have a global configuration that only needs to be set once and I feel that adding the following to each module (even calling a setup function for each module) is a bit superfluous:
def setUp(self):
Configuration.configure('some configuration settings')
I figured it out! Nose provides package-level setup and teardown as documented here. All I have to do is define the setup method in the package's __init__.py file.
Here, you can see an example of how to use the setup function. To make things simple:
lines = []
def setup():
global lines
lines.append('test') # here, we can trigger a build
# and read in a file, for example
def test_this():
assert lines[0] == 'test'
I have a data structure that is created in one function and passed onto other functions. I am trying to unit test all those functions.
Do I need to re-create that data structure (the environment) at each function? I tried using a global variable but I cannot guarantee which test case will run before the other.
I know I cannot override __init__ of unittest.TestCase without much headache.
How else can I achieve that? Passing a parameter or somehow making it a variable and avoiding a race condition?
It sounds like you do not want to redefine the data structure before each test. As long as the tests do not modify the data, I don't think there is any problem with defining the data structure in __init__:
import unittest
class Test(unittest.TestCase):
def __init__(self, methodName = 'runTest'):
unittest.TestCase.__init__(self, methodName)
self.data = range(5)
def test_getitem(self):
self.assertEqual(self.data[1],1)
def test_reversed(self):
self.assertEqual(list(reversed(self.data)),[4,3,2,1,0])
if __name__ == '__main__':
import sys
sys.argv.insert(1,'--verbose')
unittest.main(argv = sys.argv)
yields
% test.py
test_getitem (__main__.Test) ... ok
test_reversed (__main__.Test) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
I've written a function which opens a vim editor with the given filename when called.. How can I do the unittest of these types of operations....
To unit test something like this you must mock/stub out your dependencies. In this case lets say you are launching vim by calling os.system("vim").
In your unit test you can stub out that function call doing something like:
def launchVim():
os.system("vim")
def testThatVimIsLaunched():
try:
realSystem = os.system
called = []
def stubSystem(command):
if command == "vim":
called.append(True)
os.system = stubSystem
launchVim() # function under test
assert(called == [True])
finally:
os.system = realSystem
For more details on mocking and stubbing take a look at this article
Update: I added the try/finally to restore the original system function as suggested by Dave Kirby
This is no longer unittesting but integration testing. Why do you need to launch vim? Usually, you would 'mock' this, simulate the process spawning and depend on the fact that python's subprocess module is well tested.
To accomplish this in your code, you can, for example, subclass the class that implements your functionality and override the method that's responsible for spawning. Then test this subclass. I.e.
class VimSpawner(object): # your actual code, to be tested
...
def spawn(self):
... do subprocess magic
def other_logic(self):
...
self.spawn()
class TestableVimSpawner(VimSpawner):
def spawn(self):
... mock the spawning
self.ididit = True
class Test(..):
def test_spawning(self):
t = TestableVimSpawner()
t.other_logic()
self.failUnless(t.ididit)