我在测试这种情况时遇到了问题。
发票有两种状态 - 已完成和未完成 - 我想测试方法Presenter.FinishInvoice()调用DAO.FinishInvoice()然后调用DAO.GetInvoice()然后使用结果设置View.Invoice。问题是我需要调用DAO.GetInvoice()来获取发票以便在第一时间完成,这是从Presenter.InitializeView()调用的(在另一个测试中测试)。
这是我的测试:
using (mocks.Record())
{
SetupResult.For(view.Invoice).PropertyBehavior();
SetupResult.For(DAO.GetInvoice(1)).Return(invoice);
Expect.Call(DAO.FinishInvoice(1)).Return(true);
Expect.Call(DAO.GetInvoice(1)).Return(invoice);
}
using (mocks.Playback())
{
Presenter presenter = new Presenter(view, DAO);
presenter.InitializeView(1);
presenter.FinishInvoice();
}
调用InitializeView()时,将调用DAO.GetInvoice()并设置一次View.Invoice。它不是测试的一部分,但如果我没有将View.Invoice设置为未完成的发票,则FinishInvoice()将失败,因此需要设置返回值。
第二次调用DAO.GetInvoice()从FinishInvoice()调用,是测试的一部分。
如果我运行此测试,我会在DAO.GetInvoice(1)上失败;期望#1,实际#0。我已经逐步完成了代码,并在调用FinishInvoice()时调用DAO.GetInvoice(),因此它必须是我的测试代码有问题,而不是我的演示者代码。
如果我改变:
SetupResult.For(DAO.GetInvoice(1)).Return(invoice);
为:
Expect.Call(DAO.GetInvoice(1)).Return(invoice);
它有效,但不应该是测试的一部分,因为它只是设置所需(但不能放入SetUp方法,因为它不是所有测试都需要的)
我认为使用Expect.Call()并不是我需要做的灾难,但是我想学习如何设置它我想要它的方式。
答案 0 :(得分:0)
由于您要测试DAO级别的交互,因此需要创建它as a mock and not as a stub。这意味着您无法使用SetupResult。
如果您不关心方法调用的顺序,可以使用Repeat-syntax:
using (mocks.Record())
{
SetupResult.For(view.Invoice).PropertyBehavior();
Expect.Call(DAO.FinishInvoice(1)).Return(true);
Expect.Call(DAO.GetInvoice(1)).Return(invoice).Repeat.Any();
}
using (mocks.Playback())
{
Presenter presenter = new Presenter(view, DAO);
presenter.InitializeView(1);
presenter.FinishInvoice();
}
如果您关心方法调用的顺序,则必须使用Ordered-syntax明确指定每个期望:
using (mocks.Record())
{
SetupResult.For(view.Invoice).PropertyBehavior();
using (mocks.Ordered())
{
Expect.Call(DAO.GetInvoice(1)).Return(invoice);
Expect.Call(DAO.FinishInvoice(1)).Return(true);
Expect.Call(DAO.GetInvoice(1)).Return(invoice);
}
}
using (mocks.Playback())
{
Presenter presenter = new Presenter(view, DAO);
presenter.InitializeView(1);
presenter.FinishInvoice();
}
但是,如果您在yor代码中调用DAO.GetInvoice两次,我会说这是代码味道,您应该考虑将其重构为一次调用。
此外,以下是AAA-syntax from 3.5:
的情况//Arrange
DAO.Stub( x => x.GetInvoice(1) ).Return(true).Repeat.Any();
//Act
Presenter presenter = new Presenter(view, DAO);
presenter.InitializeView(1);
presenter.FinishInvoice();
//Assert
DAO.AssertWasCalled( x => x.FinishInvoice(1) );
DAO.AssertWasCalled( x=> x.GetInvoice(1) );
正如您所看到的那样,这样做更好,您甚至可以将模拟用作模拟和存根。