I am mocking out a database in some tests that I am doing. How would I create a setup method for the entire class, such that it runs each time an individual test within the class runs?
Example of what I am attempting to do.
from mocks import MockDB
class DBTests(unittest.TestCase):
def setup(self):
self.mock_db = MockDB()
def test_one(self):
#deal with self.mock_db
def test_two(self):
#deal with self.mock_db, as if nothing from test_one has happened
I'm assuming a teardown method would also be possible, but I can't find documentation that will do something like this.
If you are using Python unit test framework something like this is what you want:
class Test(unittest.TestCase):
def setUp(self):
self.mock_db = MockDB()
def tearDown(self):
pass # clean up
def test_1(self):
pass # test stuff
Documentation
With Nose, subclassing of TestCase works the same way as standard unittest -- setUp/tearDown are the same. From the nose docs
Test classes
A test class is a class defined in a test module that matches
testMatch or is a subclass of unittest.TestCase. All test classes are
run the same way: Methods in the class that match testMatch are
discovered, and a test case is constructed to run each method with a
fresh instance of the test class. Like unittest.TestCase subclasses,
other test classes can define setUp and tearDown methods that will be
run before and after each test method. Test classes that do not
descend from unittest.TestCase may also include generator methods and
class-level fixtures. Class-level setup fixtures may be named
setup_class, setupClass, setUpClass, setupAll or setUpAll; teardown
fixtures may be named teardown_class, teardownClass, tearDownClass,
teardownAll or tearDownAll. Class-level setup and teardown fixtures
must be class methods.
Related
My automation framework uses pytest setup/teardown type of testing instead of fixtures. I also have several levels of classes:
BaseClass - highest, all tests inhriet from it
FeatureClass - medium, all tests related to the programs feature inherit from it
TestClass - hold the actual tests
edit, for examples sake, i change the DB calls to a simple print
I want to add DB report in all setup/teardowns. i.e. i want that the general BaseClass setup_method will create a DB entry for the test and teardown_method will alter the entry with the results. i have tried but i can't seem to get out of method the values of currently running test during run time. is it possible even? and if not, how could i do it otherwise?
samples:
(in base.py)
class Base(object):
test_number = 0
def setup_method(self, method):
Base.test_number += 1
self.logger.info(color.Blue("STARTING TEST"))
self.logger.info(color.Blue("Current Test: {}".format(method.__name__)))
self.logger.info(color.Blue("Test Number: {}".format(self.test_number)))
# --->here i'd like to do something with the actual test parameters<---
self.logger.info("print parameters here")
def teardown_method(self, method):
self.logger.info(color.Blue("Current Test: {}".format(method.__name__)))
self.logger.info(color.Blue("Test Number: {}".format(self.test_number)))
self.logger.info(color.Blue("END OF TEST"))
(in my_feature.py)
class MyFeature(base.Base):
def setup_method(self, method):
# enable this feature in program
return True
(in test_my_feature.py)
class TestClass(my_feature.MyFeature):
#pytest.mark.parametrize("fragment_length", [1,5,10])
def test_my_first_test(self):
# do stuff that is changed based on fragment_length
assert verify_stuff(fragment_length)
so how can i get the parameters in setup_method, of the basic parent class of the testing framework?
The brief answer: NO, you cannot do this. And YES, you can work around it.
A bit longer: these unittest-style setups & teardowns are done only for compatibility with the unittest-style tests. They do not support the pytest's fixture, which make pytest nice.
Due to this, neither pytest nor pytest's unittest plugin provide the context for these setup/teardown methods. If you would have a request, function or some other contextual objects, you could get the fixture's values dynamically via request.getfuncargvalue('my_fixture_name').
However, all you have is self/cls, and method as the test method object itself (i.e. not the pytest's node).
If you look inside of the _pytest/unittest.py plugin, you will find this code:
class TestCaseFunction(Function):
_excinfo = None
def setup(self):
self._testcase = self.parent.obj(self.name)
self._fix_unittest_skip_decorator()
self._obj = getattr(self._testcase, self.name)
if hasattr(self._testcase, 'setup_method'):
self._testcase.setup_method(self._obj)
if hasattr(self, "_request"):
self._request._fillfixtures()
First, note that the setup_method() is called fully isolated from the pytest's object (e.g. self as the test node).
Second, note that the fixtures are prepared after the setup_method() is called. So even if you could access them, they will not be ready.
So, generally, you cannot do this without some trickery.
For the trickery, you have to define a pytest hook/hookwrapper once, and remember the pytest node being executed:
conftest.py or any other plugin:
import pytest
#pytest.hookimpl(hookwrapper=True)
def pytest_runtest_protocol(item, nextitem):
item.cls._item = item
yield
test_me.py:
import pytest
class Base(object):
def setup_method(self, method):
length = self._item.callspec.getparam('fragment_length')
print(length)
class MyFeature(Base):
def setup_method(self, method):
super().setup_method(method)
class TestClass(MyFeature):
#pytest.mark.parametrize("fragment_length", [1,5,10])
def test_my_first_test(self, fragment_length):
# do stuff that is changed based on fragment_length
assert True # verify_stuff(fragment_length)
Also note that MyFeature.setup_method() must call the parent's super(...).setup_method() for obvious reasons.
The cls._item will be set on each callspec (i.e. each function call with each parameter). You can also put the item or the specific parameters into some other global state, if you wish.
Also be carefull not to save the field in the item.instance. The instance of the class will be created later, and you have to use setup_instance/teardown_instance method for that. Otherwise, the saved instance's field is not preserved and is not available as self._item in setup_method().
Here is the execution:
============ test session starts ============
......
collected 3 items
test_me.py::TestClass::test_my_first_test[1] 1
PASSED
test_me.py::TestClass::test_my_first_test[5] 5
PASSED
test_me.py::TestClass::test_my_first_test[10] 10
PASSED
============ 3 passed in 0.04 seconds ============
Pytest documentation describes four ways to setup/teardown things:
module level setup/teardown
class level setup/teardown
method level setup/teardown
function level setup/teardown
But in one project it was implemented like this:
class TestClass:
def setup(self):
...
def test_1(self):
...
...
This setup method is called around each method invocation, just like setup_method from documentation (except that it doesn't take method as an argument). But I haven't seen it in the documentation or anywhere else. Why does it work?
Check this code
https://pytest.org/latest/_modules/_pytest/python.html
I would guess it's inheriting and using
def setup(self):
It's part of nose testing framework which is integrated in pytest. More information you can find here
I've written some tests using unittest as below and I want to reuse them in another class where I'm stuck and need help..
Code snippets are as below.
MyTestClass.py
Class MyTestClass(unittest.TestCase):
#classmethod
def test_TC01_set(self):
self.devAddr = "127.0.0.0"
self.teststoSkip = 'TC02'
def skip(type):
if type in self.teststoSkip:
self.skipTest('skipped!!') #unittest.Testcase method
def test_TC02(self):
self.skip('TC02')
print 'test_TC02 will do other tasks'
def test_TC03(self):
self.skip('TC03')
print 'test_TC03 will do other tasks'
This will work fine. Now I want to reuse the same testcases in another class. say,
RegressionMyTest.py
from MyTestClass import MyTestClass
Class RegressionMyTest(MyTestClass):
#classmethod
def setupmytest(self):
self.test_TC01_set(self)#this will work fine since it is accessing classmethod
self.tes_TC02(self)#cant access like this since it is not a class method
self.tes_TC03(self)#cant access like this since it is not a class method
How can I reuse the tests in MyTestClass in RegressionMyTest so that both MyTestClass and RegressionMyTest should work if they are run individually using nosetests/unittest.
Usually tests are supposed to assert code is functioning in a certain way, so I'm not sure if it would make sense to actually share tests between testsuites, (I don't think it would be very explicit)
Python tests cases are just python classes, that are introspected by the test runner for methods beginning in test_. Because of this you can you use inheritance in the same way you would with normal classes.
If you need shared functionality, you could create a base class with shared initialization methods/ helper methods. Or create testing mixins with utility functions that are needed across tests.
class BaseTestCase(unittest.TestCase):
def setUp(self):
# ran by all subclasses
def helper(self):
# help
class TestCaseOne(BaseTestCase):
def setUp(self):
# additional setup
super(TestCaseOne, self).setUp()
def test_something(self):
self.helper() # <- from base
Perhaps you don't want to define a setup method on the base class and just define on child classes using some helper methods defined in the base class? Lots of options!
I don't think your title describe your question correctly. Your code mistake is:
Calling a parent class "object method" in the child "class method"(#classmethod), because an "object method" must have one class instance(object), so in the child "class method", the system could find any object instance for its parent class.
You just need review the concepts of "class methods" and "object methods"(or instance methods) in programming language.
I've been fighting with nose and fixtures today and can't help but feel I'm doing something wrong.
I had all my tests written as functions and everything was working OK, but I want to move them to test classes as I think it's tidier and the tests can then be inherited from.
I create a connection to the testdb, the transaction to use, and a number of fixtures at a package level for all tests. This connection is used by repository classes in the application to load test data from the DB.
I tried to create my test classes with the class they are to test as an attribute. This was set in the __init__ function of the test class.
The problem I had is the class I was testing needs to be instantiated with data from my test DB, but Nose creates an instance of the test class before the package setup function is run. This mean that there are no fixtures when the test classes are created and the tests fail.
The only way I can get it to work is by adding a module setup function that defines the class I want to test as a global, then use that global in the test methods, but that seems quite hacky. Can anyone suggest a better way?
That isn't very clear, so here is an example of my test module...
from nose.tools import *
from myproject import repositories
from myproject import MyClass
def setup():
global class_to_test
db_data_repo = repositories.DBDataRepository()
db_data = db_data_repo.find(1)
class_to_test = MyClass(db_data)
class TestMyClass(object):
def test_result_should_be_an_float(self):
result = class_to_test.do_something()
assert isinstance(result, float)
If you know a better way to achieve this then please share :) thanks!
If you are moving toward unittest.TestCase class based testing, you might as well use setUp()/tearDown() method that will run before each test method, and setUpClass() to setup up class specific things, and nose will handle it just as unittest will, something like this:
class TestMyClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
db_data_repo = repositories.DBDataRepository()
db_data = db_data_repo.find(1)
cls.class_to_test = MyClass(db_data)
def test_result_should_be_an_float(self):
result = self.class_to_test.do_something()
assert isinstance(result, float)
I'm converting the test suite of a Python project from unittest to nose. The project's existing framework (based on unittest) is rather clunky, containing lots of heavily customised code for test discovery and running, so I'm trying to migrate to nose to make everything more streamlined.
I'm facing problems with the code that's generating test suites, however.
The project's framework has two ways of running tests. One is
class TestSomething(unittest.TestCase):
def setUp(self):
...
def test_x(self):
...
def test_y(self):
...
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestSomething))
which is the "straightforward" way, it's what all Nose examples and tutorials show, and it works. However, the second way is by defining a test class that contains all the test logic, then creating test cases in various subclasses that contain different setup configurations and inherit the tests from the superclass:
class TestSomething(unittest.TestCase):
def test_x(self):
...
def test_y(self):
...
class TestCase1(TestSomething):
def setUp(self):
...
class TestCase2(TestSomething):
def setUp(self):
...
suite = unittest.TestSuite()
cases = [TestCase1,TestCase2]
suite.addTests([unittest.makeSuite(case) for case in cases])
This is what Nose fails with. It tries to run the test methods first, which obviously doesn't work because there is no setUp() in the superclass and many of the variables used in test_x() and test_y() have not yet been defined.
I haven't found any examples of this done anywhere, and Nose's (rather sparse and difficult to navigate) documentation doesn't seem to mention it either. How can this be made to work with nose? Any help will be greatly appreciated.
First of all, as unutbu noted, you shouldn't give to TestSomething a name that starts with Test, because nose automatically treats such classes as test-cases. Also, nose runs all TestCase subclasses he finds, thus doing:
class Something(unittest.TestCase):
...
gives exactly the same results you are having. I think you should not inherit from TestCase and use that class as a mix-in:
class Something(object):
def test_x(self):
# here the various assertEqual etc. do not resolve, but you can use them
# as if they were present, since in real test-cases they will be inherited
# from unittest.TestCase.
...
...
class TestCase1(unittest.TestCase, Something):
def setUp(self):
...
An other way to do this is to set the class's __test__ attribute to False:
class TestSomething(unittest.TestCase):
__test__ = False
def test_x(self):
...
class TestCase1(TestSomething):
__test__ = True #must put this
def setUp(self):
...
Alternatively you can use nose.istest and nose.nottest to mark which class is a testcase and which one isn't:
#tools.nottest
class TestSomething(unittest.TestCase):
def test_x(self):
...
#tools.istest
class TestCase1(TestSomething):
sef setUp(self):
...