使用 AutoFixture 和 Moq 模拟 HttpResponse.StatusCode

Mocking HttpResponse.StatusCode with AutoFixture and Moq

我正在使用 AutoFixture as an auto-mocking container 并想模拟一个 HttpResponse 以便我可以验证是否已设置特定的 StatusCode。但是,当我调用 SetupSet:

时,我得到一个 NotImplementedException
var response = _fixture.Freeze<Mock<HttpResponseBase>>();
response
    .SetupSet(x => x.StatusCode = It.IsAny<int>());

如果我只使用 HttpResponseBase 的新 Mock,我也不会例外,但是我将不得不编写一个 FreezeMoq 扩展方法,如 Mark Seemann 的 Freezing mocks 博客中所述post.

AutoFixture 在做什么,这意味着我无法在虚拟 属性 上设置一个集合,其中基础 class 会抛出一个 NotImplementedException,但是当仅使用 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>()));
}

上面的测试通过了,表明当你将CallBase设置为true时,Moq在这种情况下抛出NotImplementedException,这正是AutoMoq[=34] =] 确实如此。

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

然而,在这种情况下,它会导致失败,因为 HttpResponseBase.StatusCode 是一个虚拟方法,它是 'implemented' 通过从 getter 和 [ 中抛出 NotImplementedException =38=]。我无法理解该设计决策如何通过代码审查。

您可以使用 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 属性.

的值