我在尝试使用RhinoMocks来确定是否在我的类中调用一个方法时遇到了一些问题,还调用了一定数量的其他方法。 我的课程要测试:
public class OrderMessageHandler : IHandleMessages<UpdateOrder>
{
public virtual IRepository Repository { get; set; }
public void Handle(UpdateOrder message)
{
if (!message.Order.Confirmed) return;
using (var om = new OperationManager())
{
try
{
om.BeginOperation();
LVR.Order.Model.OrderHeader order = ConvertToLocalOrderHeader(message.Order);
Repository.SaveUpdate(order);
om.CommitOperation();
}
catch (Exception ex)
{
om.RollbackOperation();
// other stuff here
}
}
}
internal virtual LVR.Order.Model.OrderHeader ConvertToLocalOrderHeader(Protocol.DTO.OrderHeader order)
{
// do stuff here, and call Repository.GetAll<Country>()
}
}
这是我的测试方法
[Fact]
public void ConvertToLocalOrderHeader_GivenConfirmedOrderMessage_CallTheConversionMethods()
{
// create a partial mock 'cause I want some of the implementation to be the true sut class
var sut = MockRepository.GeneratePartialMock<OrderMessageHandler>();
// create a stub for the repository, in order to avoid hitting the db
sut.Repository = MockRepository.GenerateStub<IRepository>();
sut.Repository.Stub(r => r.GetAll<Country>())
.Return(
new List<Country>
{
new Country {CountryID = "IT", Description = "Italy"},
new Country {CountryID = "US", Description = "United States"}
}.AsQueryable()
);
sut.Repository.Stub(r => r.SaveUpdate<OrderHeader>(Arg<OrderHeader>.Is.Anything));
// call the method I want to test
sut.Handle(new UpdateOrder
{
Order = order,
EventId = new Guid(),
EventTime = DateTime.Now
});
// verify that the method has been called (this is useless in my real test, I put it here just to understand why it doesn't work)
sut.AssertWasCalled(s => s.Handle(Arg<UpdateOrder>.Is.Anything));
// verify that an inner method (virtual) has been called during the execution of sut.handle()
sut.AssertWasCalled(s => s.ConvertToLocalOrderHeader(order));
}
在2 sut.AssertWasCalled
次调用中,我收到错误的对象引用未设置为对象的实例。 。原因是sut.AssertWasCalled
调用了方法,即验证......因此
sut.AssertWasCalled(s => s.Handle(Arg<UpdateOrder>.Is.Anything));
呼叫
sut.Handle(null)
如果该参数为null,则该方法抛出异常。 太糟糕了,问题是它不应该重新调用该方法,而只是告诉我它是否在测试方法之前从未被调用过。 这里有什么问题?
修改
根据评论中收到的建议,我尝试了一种不同的方法(假设我不喜欢期望/验证的味道)。这是测试方法:
[Fact]
public void ConvertToLocalOrderHeader_GivenConfirmedOrderMessage_CallTheConversionMethods2()
{
var mocks = new MockRepository();
var sut = mocks.PartialMock<OrderMessageHandler>();
sut.Repository = mocks.Stub<IRepository>();
sut.Repository.Stub(r => r.GetAll<Country>())
.Return(
new List<Country>
{
new Country {CountryID = "IT", Description = "Italy"},
new Country {CountryID = "US", Description = "United States"}
}.AsQueryable()
);
sut.Repository.Stub(r => r.SaveUpdate<OrderHeader>(Arg<OrderHeader>.Is.Anything));
Expect.Call(() => sut.Handle(Arg<UpdateOrder>.Is.Anything));
sut.Replay();
sut.Handle(new UpdateOrder
{
Order = order,
EventId = new Guid(),
EventTime = DateTime.Now
});
mocks.VerifyAll();
}
在这里,我有错误:
System.InvalidOperationException
Previous method 'OrderMessageHandler.get_Repository();' requires a return value or an exception to throw.
代码行引发错误
Expect.Call(() => sut.Handle(Arg<UpdateOrder>.Is.Anything));
所以,即使采用这种方法也没有运气......
还有其他想法吗?
答案 0 :(得分:3)
我发现了问题所在:方法ConvertToLocalOrderHeader
应至少声明为protected internal
,以便让Rhinomocks覆盖它。 Virtual
是不够的,作为测试类是一个不同的类。
解决我需要花费数小时才能解决的问题的非常简单的解决方案:/