我的 Web 应用程序对 Spotify 进行 API 调用。在我的 Flask 视图之一中,我对不同的端点使用相同的方法。具体来说:
sh = SpotifyHelper()
...
@bp.route('/profile', methods=['GET', 'POST'])
@login_required
def profile():
...
profile = sh.get_data(header, 'profile_endpoint')
...
playlist = sh.get_data(header, 'playlist_endpoint')
...
# There are 3 more like this to different endpoints -- history, top_artists, top_tracks
...
return render_template(
'profile.html',
playlists=playlists['items'],
history=history['items'],
...
)
我不想在测试期间进行 API 调用,因此我编写了一个 mock.json 来替换 API 的 JSON 响应。当每个视图仅使用该方法一次时,我已经成功完成了此操作:
class MockResponse:
@staticmethod
def profile_response():
with open(path + '/music_app/static/JSON/mock.json') as f:
response = json.load(f)
return response
@pytest.fixture
def mock_profile(monkeypatch):
def mock_json(*args, **kwargs):
return MockResponse.profile_response()
monkeypatch.setattr(sh, "get_data", mock_json)
我的问题是我需要以不同的响应调用
get_data
到不同的端点。我的mock.json是这么写的:
{'playlists': {'items': [# List of playlist data]},
'history': {'items': [# List of playlist data]},
...
因此,对于每个 API 端点,我需要类似的东西
playlists = mock_json['playlists']
history = mock_json['history']
我可以写
mock_playlists()
、mock_history()
等,但是如何为每个写一个monkeypatch?有没有办法将端点参数传递给monkeypatch.setattr(sh, "get_data", mock_???)
?
from unittest.mock import MagicMock
#other code...
mocked_response = MagicMock(side_effect=[
# write it in the order of calls you need
profile_responce_1, profile_response_2 ... profile_response_n
])
monkeypatch.setattr(sh, "get_data", mocked_response)
使用参数模拟函数的示例
"""my_module.py"""
def original_func(arg1, arg2):
print(f'original func, arg1: {arg1} and arg2 {arg2}')
def use_original_func():
arg1 = "modified_arg1_by_use_original_func"
arg2 = "modified_arg2_by_use_original_func"
original_func(arg1, arg2)
"""mock_demo.py"""
import pytest
import my_module
@pytest.fixture
def mock_original_func(monkeypatch):
def mock_query(arg1, *args, **kwargs):
print("Mocking original_func")
print(arg1, "mocked_arg2")
monkeypatch.setattr(my_module, 'original_func', mock_query)
def test_use_original_func(mock_original_func):
my_module.use_original_func()
### Output
============================= test session starts
==============================
collecting ... collected 1 item
mock_demo.py::test_use_original_func PASSED
[100%]Mocking original_func
modified_arg1_by_use_original_func mocked_arg2
============================== 1 passed in 0.01s
===============================
Process finished with exit code 0