admin管理员组文章数量:1122832
Here's a minimal reproducible example. This is with python 3.11. Besides pytest, no other dependency.
# minum_reproducible_example.py
from typing import Literal
from unittest.mock import Mock, patch
import pytest
class CustomException(Exception):
pass
class Performance:
status: Literal["ok", "failed"]
score: int
def __init__(self, status, score) -> None:
self.status = status
self.score = score
def get_score(self):
if self.status == "ok":
return self.score
else:
raise Exception("Failed")
async def get_performance():
return Performance(status="done", score=100)
async def main():
performance = await get_performance()
return performance.get_score()
async def test_main():
with patch("minum_reproducible_example.get_performance") as mocked_get_performance:
# This fails
mocked_get_performance.return_value.get_score.side_effect = CustomException(
"Mocked to always fail"
)
with pytest.raises(CustomException):
assert await main() == 100
In this example I am trying to patch get_performance
so that it returns an object whose get_score
method will always raise.
I don't understand what the correct way to patch get_performance
is because instead of raising I get coroutine object AsyncMockMixin._execute_mock_call
. This all behaves according to the documentation .mock.html#unittest.mock.AsyncMock, where calling the AsyncMock results in "an async function which will have the outcome of side_effect or return_value after it has been awaited" and clearly I am not awaiting it. This is also because by default AsyncMock.return_value will return an AsyncMock.
In fact, if I explicitly set it as Mock, it works:
async def test_main():
with patch("minum_reproducible_example.get_performance") as mocked_get_performance:
# This works
# mocked_get_performance.return_value.get_score = Mock(
# side_effect=CustomException("Mocked to always fail")
# )
with pytest.raises(CustomException):
assert await main() == 100
So an apt question is "what are you expecting then".
Is this "a good enough" way to do it? Are there better ways? Am I misunderstanding something?
Thanks.
Here's a minimal reproducible example. This is with python 3.11. Besides pytest, no other dependency.
# minum_reproducible_example.py
from typing import Literal
from unittest.mock import Mock, patch
import pytest
class CustomException(Exception):
pass
class Performance:
status: Literal["ok", "failed"]
score: int
def __init__(self, status, score) -> None:
self.status = status
self.score = score
def get_score(self):
if self.status == "ok":
return self.score
else:
raise Exception("Failed")
async def get_performance():
return Performance(status="done", score=100)
async def main():
performance = await get_performance()
return performance.get_score()
async def test_main():
with patch("minum_reproducible_example.get_performance") as mocked_get_performance:
# This fails
mocked_get_performance.return_value.get_score.side_effect = CustomException(
"Mocked to always fail"
)
with pytest.raises(CustomException):
assert await main() == 100
In this example I am trying to patch get_performance
so that it returns an object whose get_score
method will always raise.
I don't understand what the correct way to patch get_performance
is because instead of raising I get coroutine object AsyncMockMixin._execute_mock_call
. This all behaves according to the documentation https://docs.python.org/3/library/unittest.mock.html#unittest.mock.AsyncMock, where calling the AsyncMock results in "an async function which will have the outcome of side_effect or return_value after it has been awaited" and clearly I am not awaiting it. This is also because by default AsyncMock.return_value will return an AsyncMock.
In fact, if I explicitly set it as Mock, it works:
async def test_main():
with patch("minum_reproducible_example.get_performance") as mocked_get_performance:
# This works
# mocked_get_performance.return_value.get_score = Mock(
# side_effect=CustomException("Mocked to always fail")
# )
with pytest.raises(CustomException):
assert await main() == 100
So an apt question is "what are you expecting then".
Is this "a good enough" way to do it? Are there better ways? Am I misunderstanding something?
Thanks.
Share Improve this question asked Nov 22, 2024 at 17:31 largehadroncolliderlargehadroncollider 957 bronze badges1 Answer
Reset to default 1You are supposed to patch the return value of get_performance
.
with patch(
target="minum_reproducible_example.get_performance",
return_value=Mock(
spec=Performance,
**{"get_score.side_effect": CustomException("Mocked to always fail")}
)
):
本文标签:
版权声明:本文标题:python 3.x - unittest.AsyncMock: side_effect results in an coroutine instead of raising the Exception - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736301938a1931351.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论