65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Moq 在 .NET 中实现可重用 Mock

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2023 年 8 月 6 日

CPOL

2分钟阅读

viewsIcon

3330

我在测试项目中常用的实践 - 可重用 Mock

不久前,我写了一个关于在自动化测试中使用 Builder 模式的示例,我想接着分享另一个我在测试项目中常用的实践 - 可重用 Mock。

什么是 Mock?

对于那些刚接触自动化测试的朋友们来说,想象一下你有一个这样的类

public class Mailer
{
    private readonly ISmtpClient _smtpClient;

    public Mailer(ISmtpClient smtpClient)
    {
        _smtpClient = smtpClient;
    }

    public async Task SendMailAsync(SendMailRequest request)
    {
        await _smtpClient.SendAsync(new SmtpMessage()
        {
            Port = 25,
            To = request.To,
            Credentials = CredentialsFactory.GetSmtpCredentials(),
            // ...
        });
    }
}

注意:以上代码只是一个虚构的示例。这些类实际上并不存在。

如果我们想为这个类创建一个隔离的测试,而不需要实际发送任何电子邮件(即单元测试),那么我们需要一种创建 ISmtpClient 的假实例的方法,我们可以控制它,它不会实际发送邮件,但允许我们检查方法何时被调用,提供虚拟数据等。 这基本上就是一个 Mock。

使用 Moq 编写 Mock

如果我们要为上面的邮件发送类创建一个单元测试(使用 Mock),它可能看起来像这样

public class MailerTests
{
    [Fact]
    public async Task Can_send_mail()
    {
        // Arrange
        var smtp = new Mock<ISmtpClient>();
        smtp.Setup(m => m.SendAsync(It.IsAny<SmtpRequest>())).Verifiable();

        // Act
        var sut = new Mailer(smtp.Object);
        await sut.SendMailAsync(new SendMailRequest()
        {
            // 
        });

        // Assert
        smtp.Verify(); // this will throw if SendAsync was not called
    }
}

简而言之,我们创建了一个名为 smtpISmtpClient 的 Mock,设置它以 Mock SendAsync 方法,并将其标记为可验证 - 这样我们就可以稍后验证它是否被调用。我们将 Mock 传递给 Mailer(被测服务),然后稍后验证该方法是否被调用。

听起来不错!有什么问题吗?

我不会说有什么问题 - 但它可以变得更可重用。假设我们有几个其他的测试(以及潜在的其他服务,它们也有自己的测试),它们都使用 ISmtpClient。 我们每次都必须重复创建 Mock 的过程。 而相反,我们可以这样做

public class MockSmtpClient : IMock<SmtpClient>
{
    public MockSmtpClient SetupSendAsync(bool veriable = false)
    {
        var setup = Setup(m => m.SendAsync(It.IsAny<SmtpRequest>()));

        if (verifiable)
            setup.Verifiable();

        return this;
    }
}

想法是现在我们有一个可重用的 Mock,可以在多个测试中重复使用。特别是当您 Mock 的服务包含许多将被使用的方法(例如存储库和其他与数据相关的服务)时,这可以使测试代码更加简洁和易读。 这也意味着,如果您想更改所有 Mock 的设置方式(例如:使它们全部可验证),您应该比尝试更改每个 Mock<T> 实例的地方少得多。

总之,就到此为止。 还有人遵循类似的实践,或者在自动化测试方面还有其他常用实践吗? 请在评论中告诉我!

再见!

使用 Moq 在 .NET 中实现可重用 Mock - CodeProject - 代码之家
© . All rights reserved.