英文:
Pytest mock different behaviour to same function on loop
问题
I'm having troubles on mocking the return value on looped lists. Imagine I have a function that paints the cars like this:
def do_operate(car_list: list):
flawless_car_list = list()
for car in car_list:
if paint_the_car(car):
flawless_car_list.append(car)
else:
print_log(f"{car} couldn't get painted")
return flawless_car_list
On each iteration there's a some random error probability (like unable to connect to server, or couldn't get car details) that a car couldn't get painted for an unknown reason. We have tests to ensure that even a car can't get painted, we are continuing to paint the rest of the upcoming cars, and logging the erroneous cars.
If I test the happy path, everything is ok like this:
def test_happy_path(mocker):
test_list = ["honda", "bmw", "ford"]
mocker.patch("pytest1.paint_the_car", return_value=True)
mocker.patch("pytest1.print_log")
card_list = do_operate(car_list=test_list)
assert len(card_list) == 3
paint_the_car.assert_called()
print_log.assert_not_called()
But at some point I need to be able to mock the paint_car
like this mocker.patch("pytest1.paint_the_car", return_value=False)
for a specific car (second car) and mocker.patch("pytest1.paint_the_car", return_value=True)
for first and third cars. In the end, I would like to pass the assertions;
def test_error_occured_on second_item(mocker):
test_list = ["honda", "bmw", "ford"]
# HOW TO CHANGE MOCKS?
mocker.patch("pytest1.paint_the_car", return_value=True)
mocker.patch("pytest1.print_log")
card_list = do_operate(car_list=test_list)
assert len(card_list) == 2
paint_the_car.assert_called()
print_log.assert_called_with("bmw couldn't get painted")
英文:
I'm having troubles on mocking the return value on looped lists. Imagine I have a function that paints the cars like this:
def do_operate(car_list: list):
flawless_car_list = list()
for car in car_list:
if paint_the_car(car):
flawless_car_list.append(car)
else:
print_log(f"{car} couldn't get painted")
return flawless_car_list
On each iteration there's a some random error probability (like unable to connect to server, or couldn't get car details) that a car couldn't get painted for an unknown reason. We have tests to ensure that even a car can't get painted, we are continuing to paint the rest of the upcoming cars, and logging the erroneous cars.
If I test the happy path, everything is ok like this:
def test_happy_path(mocker):
test_list = ["honda", "bmw", "ford"]
mocker.patch("pytest1.paint_the_car", return_value=True)
mocker.patch("pytest1.print_log")
card_list = do_operate(car_list=test_list)
assert len(card_list) == 3
paint_the_car.assert_called()
print_log.assert_not_called()
But at some point I need to be able to mock the paint_car
like this mocker.patch("pytest1.paint_the_car", return_value=False)
for a specific car (second car) and mocker.patch("pytest1.paint_the_car", return_value=True)
for first and third cars. In the end, I would like to pass the assertions;
def test_error_occured_on_second_item(mocker):
test_list = ["honda", "bmw", "ford"]
# HOW TO CHANGE MOCKS?
mocker.patch("pytest1.paint_the_car", return_value=True)
mocker.patch("pytest1.print_log")
card_list = do_operate(car_list=test_list)
assert len(card_list) == 2
paint_the_car.assert_called()
print_log.assert_called_with("bmw couldn't get painted")
答案1
得分: 2
你可以像这样使用side_effect
与返回值列表:mocker.patch("pytest1.paint_the_car", side_effect=[True, False, True])
,然后它会在第一次和第三次调用时返回True
,在第二次调用时返回False
。
请参阅官方文档中的side effect。
英文:
You can use side_effect
with a list of return values like so: mocker.patch("pytest1.paint_the_car", side_effect = [True, False, True])
then it would return True
for the first and 3rd calls, and False
for the second call.
See official docs for side effect.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论