如何解决如何在Python上设置模拟异常行为?
我正在使用定义内部异常(github3.exceptions.UnprocessableEntity)的外部库(github3.py)。定义此异常无关紧要,所以我想创建一个副作用并设置从该异常中使用的属性。
不是经过最小验证的代码示例:
import github3
class GithubService:
def __init__(self,token: str) -> None:
self.connection = github3.login(token=token)
self.repos = self.connection.repositories()
def create_pull(self,repo_name: str) -> str:
for repo in self.repos:
if repo.full_name == repo_name:
break
try:
created_pr = repo.create_pull(
title="title",body="body",head="head",base="base",)
except github3.exceptions.UnprocessableEntity as github_exception:
extra = ""
for error in github_exception.errors:
if "message" in error:
extra += f"{error['message']} "
else:
extra += f"Invalid field {error['field']}. " # testing this case
return f"{repo_name}: {github_exception.msg}. {extra}"
我需要从异常中设置属性msg
和errors
。所以我尝试使用pytest-mock在测试代码中进行测试:
@pytest.fixture
def mock_github3_login(mocker: MockerFixture) -> MockerFixture:
"""Fixture for mocking github3.login."""
mock = mocker.patch("github3.login",autospec=True)
mock.return_value.repositories.return_value = [
mocker.Mock(full_name="staticdev/nope"),mocker.Mock(full_name="staticdev/omg"),]
return mock
def test_create_pull_invalid_field(
mocker: MockerFixture,mock_github3_login: MockerFixture,) -> None:
exception_mock = mocker.Mock(errors=[{"field": "head"}],msg="Validation Failed")
mock_github3_login.return_value.repositories.return_value[1].create_pull.side_effect = github3.exceptions.UnprocessableEntity(mocker.Mock())
mock_github3_login.return_value.repositories.return_value[1].create_pull.return_value = exception_mock
response = GithubService("faketoken").create_pull("staticdev/omg")
assert response == "staticdev/omg: Validation Failed. Invalid field head."
此代码的问题是,如果您有side_effect
和return_value
,则Python just ignores the return_value。
这里的问题是我不想知道UnprocessableEntity
的实现来调用它将正确的参数传递给它的构造函数。另外,我没有找到仅使用side_effect
的其他方法。我还尝试使用返回值并设置模拟的 class 并以这种方式使用它:
def test_create_pull_invalid_field(
mock_github3_login: MockerFixture,) -> None:
exception_mock = Mock(__class__ = github3.exceptions.UnprocessableEntity,errors=[{"field": "head"}],msg="Validation Failed")
mock_github3_login.return_value.repositories.return_value[1].create_pull.return_value = exception_mock
response = GithubService("faketoken").create_pull("staticdev/omg")
assert response == "staticdev/omg: Validation Failed. Invalid field head."
这也不起作用,不会引发异常。因此,由于我不想看到UnprocessableEntity
的约束,我不知道该如何克服这个问题。这里有什么想法吗?
解决方法
因此,根据您的示例,您实际上不需要模拟github3.exceptions.UnprocessableEntity,而只需模拟传入的resp参数。
因此以下测试应该有效:
haystackObj
编辑:
如果希望github3.exceptions.UnprocessableEntity被完全抽象,则不可能模拟整个类,因为不允许捕获不继承自BaseException的类(请参见docs)。但是您可以通过仅模拟构造函数来解决它:
def test_create_pull_invalid_field(
mocker: MockerFixture,mock_github3_login: MockerFixture,) -> None:
mocked_response = mocker.Mock()
mocked_response.json.return_value = {
"message": "Validation Failed","errors": [{"field": "head"}]
}
repo = mock_github3_login.return_value.repositories.return_value[1]
repo.create_pull.side_effect = github3.exceptions.UnprocessableEntity(mocked_response)
response = GithubService("faketoken").create_pull("staticdev/omg")
assert response == "staticdev/omg: Validation Failed. Invalid field head."
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。