目标:我正在尝试在应用程序中进行端到端测试。所以我想模拟外部通信来测试所有流程。
业务问题:
Bar
等效类:我有一个发送请求的类。
Foo
等效类:是我的用户类,它构建数据以发送请求。
runner
等价物:是执行用户某些操作的作业
再现性:
为了简化测试开发,我构建了具有类似结构的代码来重现场景:
# / (root folder)
from src.foo import Foo
def method_to_run_all_my_code():
my_foo = Foo()
res1 = my_foo.method_that_use_bar_function()
res2 = my_foo.method_that_use_bar_function_too()
return res1 + res2
if __name__ == '__main__':
method_to_run_all_my_code()
# src/foo.py
from .bar import Bar
class Foo:
def __init__(self) -> None:
self.bar = Bar()
def method_that_use_bar_function(self):
result = self.bar.bar_method()
print("[Foo] Use 1 - " + result)
return "Use 1 - " + result
def method_that_use_bar_function_too(self):
result = self.bar.bar_method()
print("[Foo] Use 2 - ", result)
return "Use 2 - " + result
# src/bar.py
class Bar:
def bar_method(self):
print("[Bar] this is a real method of bar")
return "real method"
我想在 bar_method 被
method_that_use_bar_function
(不是method_that_use_bar_function_too
)调用时模拟它,例如。
我尝试了这些测试,但我还做不到。
# tests/runner_test.py
import unittest
import pytest
from unittest.mock import patch, Mock
from runner import method_to_run_all_my_code
@pytest.mark.skip() # this use the real values
def test_initial():
res = method_to_run_all_my_code()
assert "Use 1" in res
assert "Use 2" in res
@pytest.mark.skip() # this mock Foo method
@patch("src.foo.Foo.method_that_use_bar_function", return_value="Mocked foo function use 1")
def test_mocking_bar_for_use_1(mocked_use_1):
res = method_to_run_all_my_code()
print("Final Results: ", res)
assert "Mocked foo function use 1" in res
assert "Use 2" in res
@pytest.mark.skip()
@patch("src.foo.Bar.bar_method", return_value="Bar function was mocked") # mock bar method for both use 1 and 2. I don't want this.
def test_mocking_bar_method(mocked_bar):
res = method_to_run_all_my_code()
print("Final Results: ", res)
assert "1 - Bar function was mocked" in res
assert "2 - Bar function was mocked" in res
@pytest.mark.skip() # this raise error
@patch("src.foo.Foo.method_that_use_bar_function", return_value=Mock(bar_method=Mock(return_value="Bar function was mocked to use 1")))
def test_mocking_bar_for_use_1(mocked_bar_use_1):
res = method_to_run_all_my_code()
print("Final Results: ", res)
assert "Mocked foo function use 1" in res
assert "Use 2" in res
@pytest.mark.skip() # this raise error
@patch("src.foo.Foo.method_that_use_bar_function.Bar.bar_method", return_value="Bar function was mocked to use 1")
def test_mocking_bar_for_use_1(mocked_bar_use_1):
res = method_to_run_all_my_code()
print("Final Results: ", res)
assert "Mocked foo function use 1" in res
assert "Use 2" in res
if __name__ == '__main__':
unittest.main()
有人可以帮助我吗?
一个点 测试替身 就是让一个单元测试专注于目标代码 它希望锻炼,而不用担心 协作代码的费用(延迟)或可能的错误, 比如高水平
create_user
get_user
或低级
send_request
方法。
与“下一层”交互的自动化测试, 例如创建/获取用户, 可以明智地称为“单元”测试。 但是通过一层探测的测试 到包含
send_request
的底层
更恰当地标记为“集成”测试。
改变
send_request
的实施
对于create_user
,但将其还原为
get_user
的通常行为,看起来像
简单的模拟无法解决的桥梁太远了。
显然你已经考虑过嘲讽send_request
在单元测试的整个过程中,
并拒绝了这种方法。
听起来你想介绍一些 迪 进入目标代码的公共 API, 以便备用网络传输 (比如嘲笑
send_request
)
可以作为参数提供。
要么,或者你可能想提供 一对模拟方法 每个{生产、测试}环境中的正确事情, without 改变他们调用的支持例程, 比如
send_request
.