背景
我正在修复单元测试,对于组织中的遗留代码,该测试已被长期忽略。它们是使用Rhino Mocks 3.4.0编写的,而我正努力寻找使该测试通过的方法。 Rhino Mocks文档似乎已经不见了,这里的大多数答案和博客似乎都使用了更新的3.5和3.6语法。
我对更新我们正在使用的Rhino Mocks的版本感到谨慎,因为我们有数千个单元测试,如果我们进行更新,则可能需要更新,也可能不需要。
场景:
我们有一个演示者和一个视图。演示者初始化后,它将在视图中设置一些默认的筛选器属性。过去,这两个属性都是枚举,并且通过了测试。最后的更改将其中一个属性更新为类的实例。已对测试进行了更新,以期望可以调用静态方法,该方法会创建一个具有默认值(与被测代码匹配)的实例,但是该测试现在失败,并显示错误Rhino.Mocks.Exceptions.ExpectationViolationException:无序方法调用。
一些示例代码:
public enum FilterOptions { OptionA, OptionB, OptionC }
public class OtherFilterOptions
{
public bool Filter1 { get; set;}
public bool Filter2 { get; set; }
public OtherFilterOptions(bool filter1 = true, bool filter2 = false)
{
Filter1 = filter1;
Filter2 = filter2;
}
public static OtherFilterOptions DefaultFilterOptions()
{
return new OtherFilterOptions();
}
}
public interface IToTestView
{
FilterOptions Property1 { set; }
OtherFilterOptions Property2 { set; }
}
public class ToTestPresenter
{
public IToTestView View { get; set; }
public ToTestPresenter(IToTestView view)
{
View = view;
}
public void InitialiseView()
{
View.Property1 = FilterOptions.OptionA;
View.Property2 = OtherFilterOptions.DefaultFilterOptions();
}
}
和失败的测试:
[TestFixture]
class Tests
{
[Test]
public void TestOne()
{
var mocks = new MockRepository();
var mockView = mocks.CreateMock<IToTestView>();
ToTestPresenter presenter = new ToTestPresenter(mockView);
using (mocks.Ordered())
{
mockView.Property1 = FilterOptions.OptionA;
mockView.Property2 = OtherFilterOptions.DefaultFilterOptions();
}
mocks.ReplayAll();
presenter.InitialiseView();
mocks.VerifyAll();
}
}
完整错误是
Rhino.Mocks.Exceptions.ExpectationViolationException:无序方法调用!预期的调用是:'已订购:{IToTestView.set_Property2(RhinoMocksTestApp.OtherFilterOptions); }”,但它是:“ IToTestView.set_Property2(RhinoMocksTestApp.OtherFilterOptions);'
我假设测试失败,因为要设置的值是方法调用而不是具体值。我试过使用mockView.Property2 = theVariable声明一个变量,但是错误没有改变。
我是否可以期望将Property2设置为{某些对象,其值Filter1 = true,Filter2 = false}?我已经看到使用Rhino Mocks 3.6进行类似操作的示例,但是使用3.4.0可以使用吗?
编辑:例如,这是一个通过Rhino Mocks 3.6.1的示例测试-我希望找到一些与3.4.0类似的语法(如果存在)。
[Test]
public void TestOne()
{
var mocks = new MockRepository();
var mockView = MockRepository.GenerateMock<IToTestView>();
ToTestPresenter presenter = new ToTestPresenter(mockView);
mocks.ReplayAll();
presenter.InitialiseView();
mockView.AssertWasCalled(v => v.Property1 = FilterOptions.OptionA);
mockView.AssertWasCalled(v => v.Property2 = Arg<OtherFilterOptions>.Matches(filters =>
(filters.Filter1 == true) && (filters.Filter2 == false)));
}
我正在寻找的答案是在LastCall.Constraints()方法中。将参数传递给Constraints允许您指定参数的属性值:
[Test]
public void TestOne()
{
var mocks = new MockRepository();
var mockView = mocks.CreateMock<IToTestView>();
ToTestPresenter presenter = new ToTestPresenter(mockView);
using (mocks.Ordered())
{
mockView.Property1 = FilterOptions.OptionA;
mockView.Property2 = OtherFilterOptions.DefaultFilterOptions();
LastCall.Constraints(
Property.Value("Filter1", true)
& Property.Value("Filter2", false));
}
mocks.ReplayAll();
presenter.InitialiseView();
mocks.VerifyAll();
}
有很多选项可以传递给Constraints()方法。其中一些细节on this CodeProject page
另一个选项是LastCall.IgnoreArguments(),如果您不在乎该属性实际设置为什么。