如何使用模拟测试服务的响应?
How to test response of service using mock?
我通过 post 请求获得以下服务:
import requests
class Attt():
def get_req(self):
pload = {'username': 'Olivia', 'password': '123'}
r = requests.post('https://httpbin.org/post', data=pload)
print(r.text)
print(r.content)
obj=Attt()
obj.get_req()
我想模拟请求,以便创建所需的服务响应。
我编写了如下测试:
import unittest
from unittest.mock import patch
from mock_tutorial.attt import Attt
import pandas as pd
class TestMockService(unittest.TestCase):
def test_mock(self):
fake_json = [{'test': "mock"}]
with patch('mock_tutorial.attt.requests.post') as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = fake_json
obj = Attt()
response = obj.get_req()
print('response json', response.json())
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), fake_json)
if __name__ == "__main__":
unittest.main()
但是由于 get_req
方法没有 return 响应,断言失败:AttributeError: 'NoneType' object has no attribute 'json'
。如何修改断言以检查 get_req 方法的响应是否已相应地模拟到 fake_json 变量?
这是因为您没有 return 从 Attt.get_req
获取任何东西,因此它 return 是 None
。所以在你的测试中,就像调用None.json()
一样。您应该 return 请求的响应:
...
class Attt():
def get_req(self):
...
return r
...
此外,如文档所述,您应该将代码包装在 attt.py 中,这样它就不会在导入时执行:
if __name__ == "__main__":
obj=Attt()
obj.get_req()
这看起来不错,因为这只是教程。但请注意,您已经可以使用模拟 requests
模块的库,例如 requests-mock.
更新
如果该方法不会 return 任何东西,那么我们所能做的就是通过向目标功能添加间谍来检查。但请注意,这在现实中没有意义,因为我们正在监视的是 mocked/patched 功能,即 requests.post
。这只会有利于学习目的,但实际上,最好不要添加测试,因为它根本不会增加任何价值。为此,我们可以使用 pytest-mock:
mock_tutorial/attt.py
import requests
class Attt():
def get_req(self):
pload = {'username': 'Olivia', 'password': '123'}
r = requests.post('https://httpbin.org/post', data=pload)
print(r.text)
print(r.content)
test_attt.py
from unittest.mock import patch
from mock_tutorial import attt
from mock_tutorial.attt import Attt
import pytest
def test_mock(mocker): # Run <pip install pytest-mock>
fake_json = [{'test': "mock"}]
with patch('mock_tutorial.attt.requests.post') as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = fake_json
post_spy = mocker.spy(attt.requests, "post")
obj = Attt()
response = obj.get_req()
assert post_spy.spy_return.status_code == 200
assert post_spy.spy_return.json() == fake_json
我通过 post 请求获得以下服务:
import requests
class Attt():
def get_req(self):
pload = {'username': 'Olivia', 'password': '123'}
r = requests.post('https://httpbin.org/post', data=pload)
print(r.text)
print(r.content)
obj=Attt()
obj.get_req()
我想模拟请求,以便创建所需的服务响应。 我编写了如下测试:
import unittest
from unittest.mock import patch
from mock_tutorial.attt import Attt
import pandas as pd
class TestMockService(unittest.TestCase):
def test_mock(self):
fake_json = [{'test': "mock"}]
with patch('mock_tutorial.attt.requests.post') as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = fake_json
obj = Attt()
response = obj.get_req()
print('response json', response.json())
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), fake_json)
if __name__ == "__main__":
unittest.main()
但是由于 get_req
方法没有 return 响应,断言失败:AttributeError: 'NoneType' object has no attribute 'json'
。如何修改断言以检查 get_req 方法的响应是否已相应地模拟到 fake_json 变量?
这是因为您没有 return 从 Attt.get_req
获取任何东西,因此它 return 是 None
。所以在你的测试中,就像调用None.json()
一样。您应该 return 请求的响应:
...
class Attt():
def get_req(self):
...
return r
...
此外,如文档所述,您应该将代码包装在 attt.py 中,这样它就不会在导入时执行:
if __name__ == "__main__":
obj=Attt()
obj.get_req()
这看起来不错,因为这只是教程。但请注意,您已经可以使用模拟 requests
模块的库,例如 requests-mock.
更新
如果该方法不会 return 任何东西,那么我们所能做的就是通过向目标功能添加间谍来检查。但请注意,这在现实中没有意义,因为我们正在监视的是 mocked/patched 功能,即 requests.post
。这只会有利于学习目的,但实际上,最好不要添加测试,因为它根本不会增加任何价值。为此,我们可以使用 pytest-mock:
mock_tutorial/attt.py
import requests
class Attt():
def get_req(self):
pload = {'username': 'Olivia', 'password': '123'}
r = requests.post('https://httpbin.org/post', data=pload)
print(r.text)
print(r.content)
test_attt.py
from unittest.mock import patch
from mock_tutorial import attt
from mock_tutorial.attt import Attt
import pytest
def test_mock(mocker): # Run <pip install pytest-mock>
fake_json = [{'test': "mock"}]
with patch('mock_tutorial.attt.requests.post') as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = fake_json
post_spy = mocker.spy(attt.requests, "post")
obj = Attt()
response = obj.get_req()
assert post_spy.spy_return.status_code == 200
assert post_spy.spy_return.json() == fake_json