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):
Related
Hi I would like to mock my decorator since I don't want to be actually calling/executing this function. But I can't seem to find the solution for this below are my code
# This is the decorator located in my project
# This is located in custom.mydecorators.decorator_file.custom_decorator
Base = declarative_base()
def custom_decorator(func):
#wraps(func)
def wrapper(*args, **kwargs):
print("This message is still printed even when I try to patch this function")
try:
#code here
my_var = CoolClass()
retval = func(*args, **kwargs)
except Exception as e:
#rollback code here
raise e
return retval
return wrapper
Now I'm trying to patch this using this code
patch('custom.mydecorators.decorator_file.custom_decorator', lambda x: x).start()
class TestMockDecoratorsCallingClass(unittest.TestCase):
def test_should_return_success_if_decorators_are_mocked(self):
# Code here
My decorators work properly in a non unittest file. But if I mock this decorator it fails saying that the local variable 'my_var' referenced before assignment
Note: my_var is inside the decorator I'm trying to mock/patch also the print message is still executed even when I try to patch it
I am using pytest to automate project test. I want to take some unique actions like "save_snapshot()" only when a test case fails.
Do we have something like that in pytest?
I have tried to achieve this using the teardown_method() But this method is not getting executed when a test case fails.
without using fixtures please.
I found a solution for this issue by using python decorator for each test in class:
def is_failed_decorator(func):
def wrapper(*args, **kwargs):
try:
func(*args, **kwargs)
except AssertionError:
cls_obj = args[0]
cur_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
func_name = func.__name__
# Save_snapshot().
raise
return wrapper
# Tests class
#is_failed_decorator
def test_fail(self):
assert False
worked for me :D
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
Please consider the following simplified example:
permitted = True
class is_allowed(object):
def __init__(self, some_arg):
# this is actually needed in the complete code
self.some_arg = some_arg
def __call__(self, f):
if permitted == False:
raise Exception("not authenticated to do that")
def wrapped_f(*args, **kwargs):
f(*args, **kwargs)
return wrapped_f
#is_allowed("blah")
def print_hi():
print("hi")
print_hi()
permitted = False
print_hi()
I guess the problem is that the decorator is only called once when the function print_hi() is defined. Because of that the change of the global variable has no effect. Is there any way to circumwent this behaviour?
Move the check inside of the wrapped_f
def __call__(self, f):
def wrapped_f(*args, **kwargs):
if not permitted:
raise Exception("not authenticated to do that")
f(*args, **kwargs)
return wrapped_f
Outside of the wrapped_f, it is checked at the creation of the function. Inside, it becomes part of the body of the new callable, which means it will be checked each time there is a call.
You want to realize that wrapped_f will be called instead of print_hi, so you want any behavior that should be included in the function to go inside of that.
I have a general purpose function that sends info about exceptions to an application log.
I use the exception_handler function from within methods in classes. The app log handler that is passed into and called by the exception_handler creates a JSON string that is what actually gets sent to the logfile. This all works fine.
def exception_handler(log, terminate=False):
exc_type, exc_value, exc_tb = sys.exc_info()
filename, line_num, func_name, text = traceback.extract_tb(exc_tb)[-1]
log.error('{0} Thrown from module: {1} in {2} at line: {3} ({4})'.format(exc_value, filename, func_name, line_num, text))
del (filename, line_num, func_name, text)
if terminate:
sys.exit()
I use it as follows: (a hyper-simplified example)
from utils import exception_handler
class Demo1(object):
def __init__(self):
self.log = {a class that implements the application log}
def demo(self, name):
try:
print(name)
except Exception:
exception_handler(self.log, True)
I would like to alter exception_handler for use as a decorator for a large number of methods, i.e.:
#handle_exceptions
def func1(self, name)
{some code that gets wrapped in a try / except by the decorator}
I've looked at a number of articles about decorators, but I haven't yet figured out how to implement what I want to do. I need to pass a reference to the active log object and also pass 0 or more arguments to the wrapped function. I'd be happy to convert exception_handler to a method in a class if that makes things easier.
Such a decorator would simply be:
def handle_exceptions(f):
def wrapper(*args, **kw):
try:
return f(*args, **kw)
except Exception:
self = args[0]
exception_handler(self.log, True)
return wrapper
This decorator simply calls the wrapped function inside a try suite.
This can be applied to methods only, as it assumes the first argument is self.
Thanks to Martijn for pointing me in the right direction.
I couldn't get his suggested solution to work but after a little more searching based on his example the following works fine:
def handle_exceptions(fn):
from functools import wraps
#wraps(fn)
def wrapper(self, *args, **kw):
try:
return fn(self, *args, **kw)
except Exception:
exception_handler(self.log)
return wrapper