我一直在嘲笑使用moq一段时间,总是发现自己在做这样的事情:
假设我想测试的行为是classUnderTest.DoSomething()调用l.Fatal(“我的测试消息”)一次。
//arrange
mockLogger.Setup(l => l.Fatal("My test message"));
//act
classUnderTest.DoSomething()
//assert
mockLogger.Verify(l => l.Fatal("My test message"), Times.Once());
我觉得验证调用总是重复设置,除了Times参数。即使使用不同的模拟框架,我也想知道其他人在做什么。有一个更好的方法吗?
答案 0 :(得分:4)
如果你真的需要控制它的行为,你只需要在Mock对象上进行设置,比如返回东西:
_mockRepo.SetUp(m => m.DoStuff()).Returns(someObject);
或抛出异常:
_mockRepo.SetUp(m => m.DoStuff()).Throws(new SomeExceptionType());
我假设,在您的示例中,您将记录器模拟对象传递给其他正在测试的对象,在这种情况下,删除设置调用将没有任何效果,因为仅通过创建Mock对象来完成等效设置
修改
public class Dude : IDude
{
private IAirSupport _support;
public Dude(IAirSupport support)
{
_support = support;
}
public void Advance(Place place)
{
if(place.IsUnderAttack)
{
_support.CoveringFire(place);
MoveAndFire(place);
}
}
}
嘲笑这个:
var support = new Mock<IAirSupport>();
var dude = new Dude(support.Object);
var place = new HotSpot { IsUnderFire = true };
dude.Advance(place);
support.Verify(m => m.CoveringFire(place), Times.Once());
这就是你所需要的 - 验证所有繁重的工作,没有理由进行设置。
答案 1 :(得分:2)
我同意你的观点,感觉重复。但是,在这个特定情况下,我认为您不需要调用Setup()
,因为您没有返回任何内容。如果我需要根据返回的对象断言,我通常只调用Setup()
。
最近我开始通过结构图使用AutoMocking,这促使我在基类上编写了一些快捷方式/实用工具方法来访问自动生成的模拟。然后我能够编写一个快捷方式来调用Verify()
。它可能会为您节省一两次击键...... http://evolutionarydeveloper.blogspot.co.uk/2012/10/automock-with-structuremap-and-moq.html
答案 2 :(得分:1)
尝试重新安排你的测试
//arrange
var mockLogger = new Mock<ILogger>();
var classUnderTest = new Foo(mockLogger.Object);
//act
classUnderTest.DoSomething();
//assert
mockLogger.Verify(l => l.Fatal("My test message"), Times.Once());
这样您就不需要双断言也不需要重复的测试数据。基本上我建议使用Setup
或使用Verify
语法,要么预先设置预期调用进行严格模拟。我个人更喜欢验证语法,因为断言的内容非常明确。
答案 3 :(得分:0)
我认为很多测试都是重复的,但是我不知道如何比你描述的更容易。
所有单元测试都遵循以下模式:setup-execute-assert(至少是好的)。这正是你的例子所做的优雅。你可以争论你是如何设置的,以及你如何断言,但是你已经在一行代码中完成了每一个,并找到了一个很难的方法。