使用AutoFixture和Moq模拟HttpResponse.StatusCode

Owa*_*ams 3 c# unit-testing autofixture

我使用AutoFixture作为自动模拟容器,并想要模拟一个,HttpResponse以便我可以验证StatusCode已设置特定.但是,NotImplementedException我打电话给我SetupSet:

var response = _fixture.Freeze<Mock<HttpResponseBase>>();
response
    .SetupSet(x => x.StatusCode = It.IsAny<int>());
Run Code Online (Sandbox Code Playgroud)

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

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

Mar*_*ann 6

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>()));
}
Run Code Online (Sandbox Code Playgroud)

上面的测试通过,证明NotImplementedException当你设置CallBase为Moq 时,Moq就会抛出true,这正是AutoMoq所做的.

在大多数情况下,设置CallBase为true是模拟基类的适当配置(它对接口没有影响),因为这意味着您可以信任模拟类仍然具有所有默认行为,除非您覆盖虚拟方法.这提供了以下优点:您不必Setup为所有虚拟方法调用方法,否则会导致脆弱的测试.

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

您可以使用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);
}
Run Code Online (Sandbox Code Playgroud)

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