Python decorators calling functions in different classes - python

I am attempting to write a decorator which calls on two additional functions and runs them in addition to the function it is decorating in a specific order.
I have tried something along these lines:
class common():
def decorator(setup, teardown, test):
def wrapper(self):
setup
test
teardown
return wrapper
class run():
def setup(self):
print("in setup")
def teardown(self):
print("in teardown")
#common.decorator(setup, teardown)
def test(self):
print("in test")
The final goal would be to have the decorator make the test run with the following flow setup > test > teardown. I know I am not calling on the setup and teardown correctly however. I would appreciate any help in how I should do this, I am new in using python and my knowledge of decorators involving arguments is limited.

Decorators on methods are applied when the class is being defined, which means that the setup and teardown methods are not bound at that time. This just means you need to pass in the self argument manually.
You'll also need to create an outer decorator factory; something that returns the actual decorator, based on your arguments:
def decorator(setup, teardown):
def decorate_function(test):
def wrapper(self):
setup(self)
test(self)
teardown(self)
return wrapper
return decorate_function
Demo:
>>> def decorator(setup, teardown):
... def decorate_function(test):
... def wrapper(self):
... setup(self)
... test(self)
... teardown(self)
... return wrapper
... return decorate_function
...
>>> class run():
... def setup(self):
... print("in setup")
... def teardown(self):
... print("in teardown")
... #decorator(setup, teardown)
... def test(self):
... print("in test")
...
>>> run().test()
in setup
in test
in teardown

Related

Only run setUp when a specific test requires it

How would I limit running a setUp method to only run when a specific test is run, e.g.
class Tests(unittest.TestCase):
setUpClass(cls):
#requirements for all tests
def test1(self):
#something
def test2(self):
#something else
def setUp(self):
#requirements for test 3
def test3(self):
#something requiring setup
In this case, I only want to run setUp when test3 is called
You can call a test-specific setup method inside test method, e.g.:
class Tests(unittest.TestCase):
setUpClass(cls):
#requirements for all tests
def test1(self):
#something
def test2(self):
#something else
def setUp(self):
#requirements for test 3
def test3(self):
self.prepareForTest3();
#execute test case
def prepareForTest3(self):
#do preparations here

Is there a way to run "setup" only once for the entire suite of Python tests? [duplicate]

Is there a function that is fired at the beginning/end of a scenario of tests? The functions setUp and tearDown are fired before/after every single test.
I typically would like to have this:
class TestSequenceFunctions(unittest.TestCase):
def setUpScenario(self):
start() #launched at the beginning, once
def test_choice(self):
element = random.choice(self.seq)
self.assertTrue(element in self.seq)
def test_sample(self):
with self.assertRaises(ValueError):
random.sample(self.seq, 20)
for element in random.sample(self.seq, 5):
self.assertTrue(element in self.seq)
def tearDownScenario(self):
end() #launched at the end, once
For now, these setUp and tearDown are unit tests and spread in all my scenarios (containing many tests), one is the first test, the other is the last test.
As of 2.7 (per the documentation) you get setUpClass and tearDownClass which execute before and after the tests in a given class are run, respectively. Alternatively, if you have a group of them in one file, you can use setUpModule and tearDownModule (documentation).
Otherwise your best bet is probably going to be to create your own derived TestSuite and override run(). All other calls would be handled by the parent, and run would call your setup and teardown code around a call up to the parent's run method.
I have the same scenario, for me setUpClass and tearDownClass methods works perfectly
import unittest
class Test(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls._connection = createExpensiveConnectionObject()
#classmethod
def tearDownClass(cls):
cls._connection.destroy()
Here is an example: 3 test methods access a shared resource, which is created once, not per test.
import unittest
import random
class TestSimulateLogistics(unittest.TestCase):
shared_resource = None
#classmethod
def setUpClass(cls):
cls.shared_resource = random.randint(1, 100)
#classmethod
def tearDownClass(cls):
cls.shared_resource = None
def test_1(self):
print('test 1:', self.shared_resource)
def test_2(self):
print('test 2:', self.shared_resource)
def test_3(self):
print('test 3:', self.shared_resource)
For python 2.5, and when working with pydev, it's a bit hard. It appears that pydev doesn't use the test suite, but finds all individual test cases and runs them all separately.
My solution for this was using a class variable like this:
class TestCase(unittest.TestCase):
runCount = 0
def setUpClass(self):
pass # overridden in actual testcases
def run(self, result=None):
if type(self).runCount == 0:
self.setUpClass()
super(TestCase, self).run(result)
type(self).runCount += 1
With this trick, when you inherit from this TestCase (instead of from the original unittest.TestCase), you'll also inherit the runCount of 0. Then in the run method, the runCount of the child testcase is checked and incremented. This leaves the runCount variable for this class at 0.
This means the setUpClass will only be ran once per class and not once per instance.
I don't have a tearDownClass method yet, but I guess something could be made with using that counter.
import unittest
class Test(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.shared_data = "dddd"
#classmethod
def tearDownClass(cls):
cls.shared_data.destroy()
def test_one(self):
print("Test one")
def test_two(self):
print("Test 2")
For more visit Python
unit test document

pytest how to take actions on setup failure

I am trying to find a clean way to execute some code when the setup_class method of py.test fails. Given the following example:
class TestClass:
#classmethod
def setup_class(self):
print("I am performing setup actions!")
def test_one(self):
x = "this"
assert 'h' in x
def setup_cleanup(self):
print("I want to perfrom some cleanup action!")
How do I get the setup_cleanup method to be triggered by py.test if setup raises an exception?
You can use this kind of decorator catch exceptions in the setup_class method:
def is_failed_decorator(func):
def wrapper(*args, **kwargs):
try:
func(*args, **kwargs)
except AssertionError:
# Your code here.
raise
return wrapper
#is_failed_decorator
#classmethod
def setup_class(self):

How can I set conditional decorators on setUpClass in unittest?

I want to set a conditional decorator to the setUpClass in python's unitest. I have tried the following (without a condition for now, to demonstrate the point):
import unittest
class conditional_decorator(object):
def __call__(self, func):
print ("Extra output")
return func
class First(unittest.TestCase):
#classmethod
#conditional_decorator
def setUpClass(cls):
print ("setting up")
def test1(self):
pass
if __name__ == '__main__':
unittest.main()
but I get an error
TypeError: object.__new__() takes no parameters
How can I solve this problem? Moreover, is there an easy way to 'combine' the two decorators for the setUpClass method?
When you look at the traceback line it will tell you where your error occurred. My best guess, because I dont know the rest of your code, is that in the body of your code you left an extra parameter or added an extra comma.
As for two decorators that questioned was asked here:Can I combine two decorators into a single one in Python?
*Also remove Class from setUpClass because setUp is it's own function
Just instantiate your conditional_decorator class first:
class First(unittest.TestCase):
#classmethod
#conditional_decorator() # Note the class is instantiated first.
def setUpClass(cls):
print ("setting up")
def test1(self):
pass
Or use a function instead of a class as your decorator:
def conditional_decorator(func):
print ("Extra output")
return func
class First(unittest.TestCase):
#classmethod
#conditional_decorator
def setUpClass(cls):
print ("setting up")
def test1(self):
pass
if __name__ == '__main__':
unittest.main()
Now it works:
$ python my_test.py
Extra output
setting up
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

pytest 2.3 adding teardowns within the class

I'm researching new version of pytest (2.3) and getting very excited about the new functionality where you
"can precisely control teardown by registering one or multiple
teardown functions as soon as they have performed some actions which
need undoing, eliminating the no need for a separate “teardown”
decorator"
from here
It's all pretty clear when it's used as function, but how to use it in the class?
class Test(object):
#pytest.setup(scope='class')
def stp(self):
self.propty = "something"
def test_something(self):
... # some code
# need to add something to the teardown
def test_something_else(self):
... # some code
# need to add even more to the teardown
Ok, I got it working by having a 'session'-wide funcarg finalizer:
#pytest.fixture(scope = "session")
def finalizer():
return Finalizer()
class Finalizer(object):
def __init__(self):
self.fin_funcs = []
def add_fin_func(self, func):
self.fin_funcs.append(func)
def remove_fin_func(self, func):
try:
self.fin_funcs.remove(func)
except:
pass
def execute(self):
for func in reversed(self.fin_funcs):
func()
self.fin_funcs = []
class TestSomething(object):
#classmethod
#pytest.fixture(scope = "class", autouse = True)
def setup(self, request, finalizer):
self.finalizer = finalizer
request.addfinalizer(self.finalizer.execute)
self.finalizer.add_fin_func(lambda: some_teardown())
def test_with_teardown(self):
#some test
self.finalizer.add_fin_func(self.additional_teardown)
def additional_teardown(self):
#additional teardown
Thanks #hpk42 for answering e-mails and helping me get the final version.
NOTE: together with xfailing the rest of the steps and improved scenarios this now makes a pretty good Test-Step structure
Indeed, there are no good examples for teardown yet. The request object has a addfinalizer method. Here is an example usage:
#pytest.setup(scope=...)
def mysetup(request):
...
request.addfinalizer(finalizerfunction)
...
The finalizerfunction will be called when all tests withing the scope finished execution.

Categories