调用两次时如何模拟具有相同名称的函数?
How to mock functions with same name, when called twice?
如何模拟在同一文件中使用不同参数调用两次的函数?
这是我的代码片段:
code_file.py
from prefect import Client
client = Client(
api_server = <ip of server>
)
def run_flow(name1, name2):
# some graphql queries, not shown here
value1 = client.graphql(graphql_value1, variables={'name': name1})
print("First client call return value:- ", value1)
value2 = client.graphql(graphql_value2, variables={'name': name2, 'id': value1['data'][0]['id']})
print("Second client call return value:- ", value2)
run_id = client.create_flow(id = value2['data'][0]['id'])
return run_id
code_test.py
# I want to mock these client calls.
# However when I am mocking, only the first client.graphql function is being mocked.
# How do I mock the other client.graphql and the client.create_flow function?
import unittest
import pytest
from pytest_mock import mocker
from unittest.mock import Mock
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
class test_flow(unittest.TestCase):
@patch("code_file.client.graphql", side_effect=["test1s", "test2s"])
@patch("code_file.client.create_flow", return_value="test_id")
def test_flow(self, s1):
# Below post call invokes run_flow function
response = client.post("/name1/name2")
assert run_flow("name1", "name2") == "test_id"
对 graphql 的第一次模拟调用成功。第二个 graphql 调用没有被嘲笑。它正在尝试联系实际服务器并收到 404。
我如何模拟两个 graphql 客户端调用?
我试图重现你的代码,但对我来说 client.graphql
被完美地模拟了。
这是我的代码。
文件夹结构
├── code_file.py
├── code_test.py
└── prefect.py
# prefect.py
class Client:
def __init__(self, *arg, **kwargs):
...
def graphql(self, *args, **kwargs):
print(f"graphql got called with args: {args}, kwargs: {kwargs}")
def create_flow(self, *args, **kwargs):
print(f"create_flow got called with args: {args}, kwargs: {kwargs}")
# code_file.py
from prefect import Client
graphql_value1 = "graphql_value1"
graphql_value2 = "graphql_value2"
client = Client(api_server="http://example.com")
def run_flow(name1, name2):
# some graphql queries, not shown here
value1 = client.graphql(graphql_value1, variables={"name": name1})
print("First client call return value:- ", value1)
value2 = client.graphql(graphql_value2, variables={"name": name2, "id": value1["data"][0]["id"]})
print("Second client call return value:- ", value2)
run_id = client.create_flow(id=value2["data"][0]["id"])
return run_id
# code_test.py
import unittest
from unittest.mock import patch, MagicMock, call
from code_file import run_flow
class TestFlow(unittest.TestCase):
@patch("code_file.client.graphql")
@patch("code_file.client.create_flow")
def test_flow(self, create_flow: MagicMock, graphql: MagicMock) -> None:
first_graphql_return_value = {"data": [{"id": 1}]}
second_graphl_return_value = {"data": [{"id": 2}]}
graphql.side_effect = [
first_graphql_return_value,
second_graphl_return_value,
]
create_flow.return_value = "test_id"
self.assertEqual(run_flow("name1", "name2"), "test_id")
create_flow.assert_called_once_with(id=2)
graphql.assert_has_calls(
[
call("graphql_value1", variables={"name": "name1"}),
call("graphql_value2", variables={"name": "name2", "id": 1})
]
)
运行 使用命令进行单元测试
python -m unittest code_test.py
产生以下输出
First client call return value:- {'data': [{'id': 1}]}
Second client call return value:- {'data': [{'id': 2}]}
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
您会看到 prefect.Client
方法中的打印没有打印出来。
原回答
说明
来自python官方文档
If side_effect is an iterable then each call to the mock will return the next value from the iterable.
当您使用可迭代对象设置 side_effect
参数时,模拟将从可迭代对象中 return 下一个值。可以找到更多详细信息 here
解决方案
def test_flow(mocker):
# Some lines of code, not shown here
m = mocker.patch("code_file.client.graphql", side_effect=["value1", "value2"])
...
如何模拟在同一文件中使用不同参数调用两次的函数? 这是我的代码片段:
code_file.py
from prefect import Client
client = Client(
api_server = <ip of server>
)
def run_flow(name1, name2):
# some graphql queries, not shown here
value1 = client.graphql(graphql_value1, variables={'name': name1})
print("First client call return value:- ", value1)
value2 = client.graphql(graphql_value2, variables={'name': name2, 'id': value1['data'][0]['id']})
print("Second client call return value:- ", value2)
run_id = client.create_flow(id = value2['data'][0]['id'])
return run_id
code_test.py
# I want to mock these client calls.
# However when I am mocking, only the first client.graphql function is being mocked.
# How do I mock the other client.graphql and the client.create_flow function?
import unittest
import pytest
from pytest_mock import mocker
from unittest.mock import Mock
from fastapi.testclient import TestClient
from app.main import app
client = TestClient(app)
class test_flow(unittest.TestCase):
@patch("code_file.client.graphql", side_effect=["test1s", "test2s"])
@patch("code_file.client.create_flow", return_value="test_id")
def test_flow(self, s1):
# Below post call invokes run_flow function
response = client.post("/name1/name2")
assert run_flow("name1", "name2") == "test_id"
对 graphql 的第一次模拟调用成功。第二个 graphql 调用没有被嘲笑。它正在尝试联系实际服务器并收到 404。 我如何模拟两个 graphql 客户端调用?
我试图重现你的代码,但对我来说 client.graphql
被完美地模拟了。
这是我的代码。
文件夹结构
├── code_file.py
├── code_test.py
└── prefect.py
# prefect.py
class Client:
def __init__(self, *arg, **kwargs):
...
def graphql(self, *args, **kwargs):
print(f"graphql got called with args: {args}, kwargs: {kwargs}")
def create_flow(self, *args, **kwargs):
print(f"create_flow got called with args: {args}, kwargs: {kwargs}")
# code_file.py
from prefect import Client
graphql_value1 = "graphql_value1"
graphql_value2 = "graphql_value2"
client = Client(api_server="http://example.com")
def run_flow(name1, name2):
# some graphql queries, not shown here
value1 = client.graphql(graphql_value1, variables={"name": name1})
print("First client call return value:- ", value1)
value2 = client.graphql(graphql_value2, variables={"name": name2, "id": value1["data"][0]["id"]})
print("Second client call return value:- ", value2)
run_id = client.create_flow(id=value2["data"][0]["id"])
return run_id
# code_test.py
import unittest
from unittest.mock import patch, MagicMock, call
from code_file import run_flow
class TestFlow(unittest.TestCase):
@patch("code_file.client.graphql")
@patch("code_file.client.create_flow")
def test_flow(self, create_flow: MagicMock, graphql: MagicMock) -> None:
first_graphql_return_value = {"data": [{"id": 1}]}
second_graphl_return_value = {"data": [{"id": 2}]}
graphql.side_effect = [
first_graphql_return_value,
second_graphl_return_value,
]
create_flow.return_value = "test_id"
self.assertEqual(run_flow("name1", "name2"), "test_id")
create_flow.assert_called_once_with(id=2)
graphql.assert_has_calls(
[
call("graphql_value1", variables={"name": "name1"}),
call("graphql_value2", variables={"name": "name2", "id": 1})
]
)
运行 使用命令进行单元测试
python -m unittest code_test.py
产生以下输出
First client call return value:- {'data': [{'id': 1}]}
Second client call return value:- {'data': [{'id': 2}]}
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
您会看到 prefect.Client
方法中的打印没有打印出来。
原回答
说明
来自python官方文档
If side_effect is an iterable then each call to the mock will return the next value from the iterable.
当您使用可迭代对象设置 side_effect
参数时,模拟将从可迭代对象中 return 下一个值。可以找到更多详细信息 here
解决方案
def test_flow(mocker):
# Some lines of code, not shown here
m = mocker.patch("code_file.client.graphql", side_effect=["value1", "value2"])
...