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.
# 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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With