Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

py.test patch on fixture

Tags:

I use the following to mock constant values for a test with py.test:

@patch('ConstantsModule.ConstantsClass.DELAY_TIME', 10)
def test_PowerUp():
    ...
    thing = Thing.Thing()
    assert thing.a == 1

This mocks DELAY_TIME as used in both the test, and in Thing, which is what I expected.

I wanted to do this for all the tests in this file, so I tried

@patch('ConstantsModule.ConstantsClass.DELAY_TIME', 10)
@pytest.fixture(autouse=True)
def NoDelay():
    pass

But that doesn't seem to have the same effect.

Here is a similar question: pytest-mock mocker in pytest fixture, but the mock seems done in a non-decorator way there.

like image 718
sg_man Avatar asked Apr 26 '18 16:04

sg_man


People also ask

What does patch do in pytest?

This, along with its subclasses, will meet most Python mocking needs that you will face in your tests. The library also provides a function, called patch() , which replaces the real objects in your code with Mock instances.

What is a test fixture Python?

Pytest fixtures are functions that can be used to manage our apps states and dependencies. Most importantly, they can provide data for testing and a wide range of value types when explicitly called by our testing software. You can use the mock data that fixtures create across multiple tests.

How do you use test fixtures?

To access the fixture function, the tests have to mention the fixture name as input parameter. Pytest while the test is getting executed, will see the fixture name as input parameter. It then executes the fixture function and the returned value is stored to the input parameter, which can be used by the test.

Does pytest have mock?

In pytest , mocking can replace the return value of a function within a function. This is useful for testing the desired function and replacing the return value of a nested function within that desired function we are testing.


2 Answers

I'd say patching via decorator is not the optimal approach here. I'd use the context manager:

import pytest
from unittest.mock import patch


@pytest.fixture(autouse=True)
def no_delay():
    with patch('ConstantsModule.ConstantsClass.DELAY_TIME', 10):
        yield

This way, patching is cleanly reverted on test teardown.

like image 198
hoefling Avatar answered Oct 12 '22 13:10

hoefling


pytest provides builtin patching support via the monkeypatch fixture. So to patch the constant for all tests in the file you can create the following autouse fixture:

@pytest.fixture(autouse=True)
def no_delay(monkeypatch):
    monkeypatch.setattr(ConstantsModule.ConstantsClass, 'DELAY_TIME', 10)

If you don't want to have the ConstantsModule imported in your tests you can use a string, see the full API reference.

like image 45
flub Avatar answered Oct 12 '22 13:10

flub