itscarlayall
itscarlayall

Reputation: 166

Unittest mock: return function which receives one pytest fixture and one argument

I'm creating some unit tests and using pytest fixtures in combination with some unittest.mock patch.object calls.

I would like to reuse a function that is called by some of my tests. It makes use of a pytest fixture (specified as the first "argument" of the function) and it requires an additional argument. It looks something like this:

import pandas as pd
import pytest
import os
from unittest.mock import patch

@pytest.fixture()
def rootdir():
    return os.path.dirname(os.path.abspath(__file__))

def my_mock_ret(rootdir, number):
    print(f"{rootdir}_{number}")
    return f"{rootdir}_{number}"

def test_simple(rootdir):
    a = pd.DataFrame()
    with patch.object(a, 'to_csv', lambda x: my_mock_ret(rootdir, x)) as _:
        a.to_csv(rootdir)

The tricky part is how to pass the number argument to my_mock_ret while also being able to access the rootdir fixture from inside it.

I've tried this way using lambda but it does not work.

Edit

It works if y put my_mock_ret inside test_simple, but I don't want to do that because I want to reuse my_mock_ret for several other tests:

import pandas as pd
import pytest
import os
from unittest.mock import patch

@pytest.fixture()
def rootdir():
    return os.path.dirname(os.path.abspath(__file__))

def test_simple(rootdir):
    def my_mock_ret(number):
        print(f"{rootdir}_{number}")
        return f"{rootdir}_{number}"

    a = pd.DataFrame()
    with patch.object(a, 'to_csv', my_mock_ret) as _:
        a.to_csv(rootdir)

Upvotes: 0

Views: 120

Answers (1)

tituszban
tituszban

Reputation: 5152

What you need right here, is the factory pattern:

import pandas as pd
import pytest
import os
from unittest.mock import patch

@pytest.fixture()
def rootdir():
    return os.path.dirname(os.path.abspath(__file__))

@pytest.fixture()
def my_mock_ret(rootdir):
    def _my_mock_ret(number):
        print(f"{rootdir}_{number}")
        return f"{rootdir}_{number}"
    return _my_mock_ret

def test_simple(my_mock_ret, rootdir):
    a = pd.DataFrame()
    with patch.object(a, 'to_csv', my_mock_ret) as _:
        a.to_csv(rootdir)

here my_mock_ret will create a function, which captures rootdir, and can take the number argument.

Upvotes: 1

Related Questions