Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make pytest fixtures work with decorated functions?

py.test seems to fail when I decorate test functions which has a fixture as an argument.

def deco(func):      @functools.wraps(func)     def wrapper(*args, **kwargs):         return func(*args, **kwargs)      return wrapper   @pytest.fixture def x():     return 0  @deco def test_something(x):     assert x == 0 

In this simple example, I get the following error:

TypeError: test_something() takes exactly 1 argument (0 given). 

Is there a way to fix this, preferably without modifying the decorator too much? (Since the decorator is used outside testing code too.)

like image 725
jck Avatar asked Oct 27 '13 04:10

jck


People also ask

Is pytest fixture a decorator?

pytest. fixture decorator makes it possible to inject the return value in the test functions whose have in their signature the decorated function name. Easy, isn't it? You can potentially generate and create everything you need in these fixture-functions and then use it in all the tests you need.

When using the pytest library which decorator defines fixtures in Python?

fixture decorator, described below. Pytest has useful built-in fixtures, listed here for reference: capfd. Capture, as text, output to file descriptors 1 and 2 .

Which is the decorator used to mark a function as a fixture?

usefixtures("fixture-name") . This special decorator adds the fixture to a test class, and the fixture will be executed before any test function.


2 Answers

It looks like functools.wraps does not do the job well enough, so it breaks py.test's introspection.

Creating the decorator using the decorator package seems to do the trick.

import decorator  def deco(func):     def wrapper(func, *args, **kwargs):         return func(*args, **kwargs)     return decorator.decorator(wrapper, func) 
like image 118
jck Avatar answered Oct 01 '22 17:10

jck


Fixture feature depends on test function signature.

If you can change wrapper signature as follow, it will works.

def deco(func):     @functools.wraps(func)     def wrapper(x):         return func(x)     return wrapper 

If you can't change it, make another decorator:

def deco(func):     @functools.wraps(func)     def wrapper(*args, **kwargs):         return func(*args, **kwargs)     return wrapper  def deco_x(func):     @functools.wraps(func)     def wrapper(x):         return func(x)     return wrapper 

And decorate test_somthing with deco_x:

@deco_x @deco def test_something(x):     assert x == 0 
like image 39
falsetru Avatar answered Oct 01 '22 17:10

falsetru