在 Rhino Mocks 3.4.0 中测试 属性 设置为新对象的实例

Testing a property set to an instance of a new object in Rhino Mocks 3.4.0

背景

我正在修复我们组织中遗留代码长期被忽视的单元测试。它们是使用 Rhino Mocks 3.4.0 编写的,我正在努力寻找一种方法让这个测试通过。 Rhino Mocks 文档似乎已经消失,这里的大多数答案和博客似乎都使用更新的 3.5 和 3.6 语法。

我对更新我们正在使用的 Rhino Mocks 版本持谨慎态度,因为我们有数千个单元测试,如果我们更新,这些单元测试可能需要也可能不需要更新。

场景:

我们有一个 Presenter 和一个 View。当 Presenter 初始化时,它会在 View 中设置一些默认的过滤器属性。在过去,这两个属性都是枚举并且测试通过。 最后一次更改将其中一个属性更新为 class 的实例。测试已更新为期望调用静态方法,该方法创建具有默认值的实例(与被测代码匹配),但测试现在失败并显示错误 Rhino.Mocks.Exceptions.ExpectationViolationException : Unordered method call.

一些示例代码:

    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 : Unordered method call! The expected call is: 'Ordered: { IToTestView.set_Property2(RhinoMocksTestApp.OtherFilterOptions); }' but was: '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() 方法中。将参数传递给约束允许您指定参数的 属性 值:

[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()。