Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test using patch with a side effect with Pytest parametrize?

I'm trying to test my function that takes in 3 arguments and also contains another function which I'm trying to mock. The issue is that the mock does not cycle through the side effect; I can't 'match' the first set of values I want to test (the first parametrized arguments) with the first value in the side effect; the second set of parametrized arguments with the second value in the side effect and so forth.

I tried to use fixtures and played around with parametrize but to no avail.

TEST CODE

# I go through each set of values I want to test with a different expected output
@pytest.mark.parametrize('banner, year, month, expected', [
    ('ctr', 2019, 1, r'A\path\file.csv'),
    ('mks', 2019, 1, r'B\path\file.csv'),
    ('sc', 2019, 1, r'C\path\file.csv'),
    ('atm', 2019, 1, r'D\path\file.csv')
])
@mock.patch('import.path.to.function.path_formatting')
def test_files(mock_directory_path_banner, banner, year, month, expected):
    # the mocked function always returns 'ctr'
    mock_directory_path_banner.side_effect = ['ctr', 'mww', 'fgl', 'fgl']
    result = get_loyalty_sales_files(banner, year, month)
    assert expected == result

In total, there are four tests. The first passes as the parameterized test uses the correct value from the mock (ctr). However the remaining tests all fail because a new mock is not called for each parameterized test. I expect that a new mock is called each time a new parameterized set of values is cycled through, but that's not the case.

like image 694
ShockDoctor Avatar asked Aug 06 '19 17:08

ShockDoctor


People also ask

How do you pass fixtures in Parametrize pytest?

You want to pass a fixture to parametrize. Suppose that you have a simple function called is_even(n) that returns true if n is divisible by 2. Then you create a simple test for it that receives a fixture named two that returns 2. To make the test more robust, you set up another fixture named four that returns 4.

How does pytest Parametrize work?

pytest will build a string that is the test ID for each set of values in a parametrized test. These IDs can be used with -k to select specific cases to run, and they will also identify the specific case when one is failing. Running pytest with --collect-only will show the generated IDs.

Which arguments can we pass to pytest Mark Parametrize to simplify testing Python code?

Summary. You can pass arguments to fixtures with the params keyword argument in the fixture decorator, and you can also pass arguments to tests with the @pytest.


1 Answers

In the file with get_loyalty_sales_files you have something like this

import path.to.function.path_formatting

Don't use this in the @patch, instead use the same path as you would import the module locally, and then append the function you want to mock:

@patch('path.to.file.with.get_loyalty_sales_files.path_formatting')

More information on how mock.patch works can be found in the mock docs.

like image 181
Василий Ковальченко Avatar answered Nov 21 '22 06:11

Василий Ковальченко