Mocking HttpResponse.StatusCode with AutoFixture and Moq

本文关键字:and Moq AutoFixture with HttpResponse StatusCode Mocking | 更新日期: 2023-09-27 18:32:23

我正在使用AutoFixture作为自动模拟容器,并希望模拟HttpResponse,以便我可以验证是否已设置特定的StatusCode。但是,当我打电话给SetupSet时,我得到了一个NotImplementedException

var response = _fixture.Freeze<Mock<HttpResponseBase>>();
response
    .SetupSet(x => x.StatusCode = It.IsAny<int>());

如果我只是使用一个新的 Mock of HttpResponseBase ,我不会有任何例外,但是我将不得不编写一个FreezeMoq扩展方法,如 Mark Seemann 的 Frozen Mocks 博客文章中所解释的那样。

AutoFixture 在做什么,这意味着我无法在基类抛出NotImplementedException的虚拟属性上设置一个集合,但是在仅使用 Moq 时可以设置?

Mocking HttpResponse.StatusCode with AutoFixture and Moq

Moq 的行为方式,您可以在没有 AutoFixture 的情况下重现该行为:

[Fact]
public void ReducedRepro()
{
    var response = new Mock<HttpResponseBase>();
    response.CallBase = true;
    Assert.Throws<NotImplementedException>(() =>
        response.SetupSet(x => x.StatusCode = It.IsAny<int>()));
}

上面的测试通过,证明当您将 Moq 设置为 CallBase 时,在这种情况下会抛出NotImplementedException true ,这正是 AutoMoq 所做的。

在大多数情况下,将 CallBase 设置为 true 是模拟基类的适当配置(它对接口没有影响),因为这意味着您可以相信模拟类仍然具有所有默认行为,除非您重写虚拟方法。这样做的好处是,您不必为所有虚拟方法调用Setup方法,否则会导致测试变脆。

但是,在这种情况下,它会导致失败,因为HttpResponseBase.StatusCode是一个虚拟方法,通过从getter和setter中抛出NotImplementedException来实现。这个设计决策是如何通过代码审查的,这超出了我的想象。

您可以使用SetupProperty相当轻松地解决它:

[Fact]
public void Workaround()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());
    var response = fixture.Freeze<Mock<HttpResponseBase>>();
    response.SetupProperty(x => x.StatusCode);
    response.Object.StatusCode = 42;
    Assert.Equal(42, response.Object.StatusCode);
}

此测试通过,表明您现在可以分配和读取 StatusCode 属性的值。