2016-01-29 71 views
3

我正在使用AutoFixture as an auto-mocking container并且想要模拟HttpResponse以便我可以验证是否已设置了特定的StatusCode。但是,我得到一个NotImplementedException当我打电话SetupSet使用AutoFixture和Moq嘲笑HttpResponse.StatusCode

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

如果我只是用的HttpResponseBase一个新的模拟,我没有得到任何异常,但我会写一个FreezeMoq扩展方法,如马克塞曼的解释Freezing mocks博客文章。

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

回答

6

起订量的行为这种方式,你可以复制不AutoFixture行为:以上测试通过

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

,表明起订量在这种情况下抛出NotImplementedException当您设置CallBasetrue,这正是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属性的值。

+0

感谢万马克! 'SetupProperty'和'CallBase'对我来说是新的,现在我已经学到了更多关于Moq和AutoFixture的知识;) –