当前位置: 首页 > 工具软件 > moq > 使用案例 >

Moq被遗忘的功能

云骏奇
2023-12-01

目录

介绍

背景

使用代码

兴趣点


介绍

给出了如何经常使用Moq以及如何改进这种工作方式的解释。

背景

如果您对.NET Core中的xUnit,模拟和固定装置(fixtures)有一定的经验,这将非常有帮助。此处显示的测试是针对.NET Core编写的,但是大多数代码都可以在使用其他单元测试框架的情况下使用。如果您不熟悉固定装置(fixtures),建议阅读这篇文章。如果您不熟悉Moq,建议阅读此文章

使用代码

我们从要测试的代码开始:

[HttpGet("{queryEntry}", Name = "GetNumberOfCharacters")]
public async Task<ActionResult<int>> GetNumberOfCharacters(string queryEntry)
{
    var numberOfCharacters = 
        await _searchEngineService.GetNumberOfCharactersFromSearchQuery(queryEntry);
    return Ok(numberOfCharacters);
}

使用AutoFixture.AutoMoqNuGet软件包在此处)可以轻松进行单元测试。使用测试的安排(arrange)部分中的Freeze方法创建模拟并进行验证,并使用Verify 方法在测试结束时进行模拟。在两者之间调用Create方法以创建包含我们要测试的方法的实例。代码如下所示:

[Fact]
public async Task GetTest()
{
    // arrange
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var service = fixture.Freeze<Mock<ISearchEngineService>>();
    service.Setup(a => a.GetNumberOfCharactersFromSearchQuery(It.IsNotNull<string>()))
        .ReturnsAsync(8);

    var controller = fixture.Build<SearchEngineController>().OmitAutoProperties().Create();

    // act
    var response = await controller.GetNumberOfCharacters("Hoi");

    // assert
    Assert.Equal(8, ((OkObjectResult)response.Result).Value);
    service.Verify(s => s.GetNumberOfCharactersFromSearchQuery("Hoi"), Times.Once);
}

另外,我们可以创建一个集成测试(而不是仅一个单元测试),该集成测试仅解析Startup类中设置的所有依赖项,并替换我们要模拟的单个依赖项。主要优点是我们可以获得更好的代码覆盖率(因为Startup类和Program类被触发)。主要缺点是我们的隔离度较低,因此通常不会替代单元测试。可以使用IntegrationFixtureNuGet在此处)完成,这就是代码的样子:

[Fact]
public async Task GetTestFreeze()
{
    // arrange
    await using (var fixture = new Fixture<Startup>())
    {
        var service = fixture.Freeze<Mock<ISearchEngineService>>();
        service.Setup(a => a.GetNumberOfCharactersFromSearchQuery(It.IsNotNull<string>()))
            .ReturnsAsync(8);

        var controller = fixture.Create<SearchEngineController>();

        // act
        var response = await controller.GetNumberOfCharacters("Hoi");

        // assert
        Assert.Equal(8, ((OkObjectResult) response.Result).Value);
        service.Verify(s => s.GetNumberOfCharactersFromSearchQuery("Hoi"), Times.Once);
    }
}

这段代码看起来不错,但是在两个测试中都出错了。我们没有验证是否对模拟进行了其他任何调用。这听起来可能无关紧要,但事实并非如此。其他调用可能仅引起副作用,而副作用通常是导致生产问题的主要原因。这是两个测试结束时所需的额外代码:

service.VerifyNoOtherCalls();

很容易忘记这一点。Moq 4.7自动附带了AutoFixture.AutoMoq不支持此方法的文件。为了能够调用它,需要单独安装一个更新的版本(至少4.8)。此外, Moq版本本身没有附带IntegrationFixture,因此对于这种情况,您需要单独安装。这种方法确实有助于防止副作用,但很容易忘记。如果您想查看所有代码:它位于GitHub

兴趣点

我很难学到这种方法。我发现了一个由实际副作用引起的实际生产问题,以防万一我会使用VerifyNoOtherCalls方法。希望本文能帮助您避免犯同样的错误。

 类似资料: