[英]How to use pytest-mock to spy on function
I have a class in foo.py that I wish to test:我在 foo.py 中有一个 class 我想测试:
import requests
class Foo:
def fooMethod(self, url):
response = requests.get(url)
return response
I want to replace the requests call to simulate the response.我想替换 requests 调用来模拟响应。
Here is my test file in test_foo.py:这是我在 test_foo.py 中的测试文件:
from foo import Foo
def mocked_requests_get(*args, **kwargs):
class MockResponse:
def __init__(self, text, code):
self.text = text
self.code = code
if args[0] == "http://localhost":
return MockResponse("Test response", 200)
return MockResponse(None, 404)
class TestFoo:
def test_foo(self, mocker):
a = Foo()
mocker.patch ('foo.requests.get', mocked_requests_get)
spy = mocker.spy (a, 'test_foo.mocked_requests_get')
response = a.fooMethod("http://localhost")
assert response.text == "Test response"
assert spy.call_count == 1
I want to check that the mocked_requests_get function is called only once.我想检查 mocked_requests_get function 是否只被调用一次。
The interpreter gives an error on the spy = mocker.spy... line: 'Foo' object has no attribute 'test_foo.mocked_requests_get'解释器在 spy = mocker.spy... 行给出错误:'Foo' object has no attribute 'test_foo.mocked_requests_get'
This is understandable - but I can't work out a way to get to the object instance that references that function.这是可以理解的——但我无法找到引用 function 的 object 实例的方法。 Can anyone help please?有人可以帮忙吗?
Your approach is a bit too complicated - you can just use a standard mock without the need to implement your own mock class.您的方法有点太复杂了——您可以只使用标准模拟,而无需实现自己的模拟 class。 Something like this should work:像这样的东西应该工作:
class TestFoo:
def test_foo(self, mocker):
a = Foo()
get_mock = mocker.patch('requests.get')
get_mock.return_value.text = "Test response"
response = a.fooMethod()
assert response.text == "Test response"
assert get_mock.call_count == 1
Also note that you have to patch requests.get
instead of foo.requests.get
, because you import requests
directly (see where to patch ).另请注意,您必须修补requests.get
而不是foo.requests.get
,因为您直接导入requests
(请参阅修补位置)。
UPDATE:更新:
If you need the response to depend on the url, as shown in the updated question, you could use side_effect
, which can take a function or class object (unless return_value
, which needs an evaluated value): If you need the response to depend on the url, as shown in the updated question, you could use side_effect
, which can take a function or class object (unless return_value
, which needs an evaluated value):
class MockedResponse:
def __init__(self, url):
self.url = url
@property
def text(self):
responses = {"url1": "response1",
"url2": "response2",
"url3": "response3"}
if self.url in responses:
return responses[self.url]
return "default"
class TestFoo:
def test_foo(self, mocker):
a = Foo()
get_mock = mocker.patch('requests.get')
get_mock.side_effect = MockedResponse
response = a.fooMethod("url2")
assert response.text == "response2"
assert get_mock.call_count == 1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.