首页 > 解决方案 > 如何使用 Python 模拟抽象类或接口 - 使用 pytest 进行测试

问题描述

我创建了一个界面来为我的控制器提供电子邮件验证

class EmailValidatorInterface(ABC):
    """ Interface to EmailValidator use case """

    @abstractmethod
    def is_valid(self, email: str) -> bool:
        """ Specific case """

        raise Exception("Should implement method: is_valid")

那是我的控制器实现

class SignUpController(RouteInterface):
    def __init__(self, emailValidator: EmailValidatorInterface):
        self.emailValidator = emailValidator

    def route(self, http_request: Type[HttpRequest]) -> HttpResponse:

如何为我的 EmailValidator 创建一个模拟?我正在尝试使用 mock.patch 但我不知道如何初始化模拟

看看我的测试

def test_should_return_400_if_invalid_param_is_provided():

    with mock.patch('EmailValidatorStub') as MockEmailValidator:
        MockEmailValidator.return_value.is_valid.return_value = False

    sut = SignUpController(EmailValidatorStub())
    attributes = {
        "name": faker.word(),
        "login": faker.word(),
        "email": "any_email",
        "email_confirmation": "any_email@mail.com",
        "password": "any_password",
        "password_confirmation": "any_password"
    }

    request = HttpRequest(body=attributes)
    httpResponse = sut.route(request)
    assert httpResponse.status_code == 500



标签: pythonunit-testingtestingpytesttestunit

解决方案


我认为你不需要mock.patch在这里,因为你可以使用依赖注入。换句话说,只需像往常一样创建一个子类,但添加特定于测试的实现:

class MockValidator(EmailValidatorInterface):
   pass

然后在您的测试中实例化它:

sut = MockValidator()

您可以为您正在测试的每个场景创建一个单独的模拟类,也可以添加一个__init__()方法,该方法采用可以在每个场景之间变化的参数。或者两者的某种组合。模拟不应该包含任何逻辑,而只是满足测试的特定场景。


推荐阅读