【问题标题】:Rhino Mocks: AAA Synax: Assert property was set with a given typeRhino Mocks:AAA Synax:断言属性设置为给定类型
【发布时间】:2011-03-18 01:45:29
【问题描述】:

我试图断言模拟对象中的属性是使用给定类型设置的。该属性具有抽象类型,并设置为多种具体类型之一。

这就是我正在尝试做的事情,无论 Foo.DoSomething() 设置 Foo.Bar 的值如何,它总是通过测试:

    [Test]
    public void DoSomething_SetsCorrectBar()
    {
        // Arrange
        Foo foo = MockRepository.GenerateMock<Foo>(); // Creates mock in Replay mode (what I want for AAA syntax).

        // Act
        foo.DoSomething();

        // Assert that DoSomething set Foo.Bar to an instance of CorrectBarSubclass
        foo.AssertWasCalled(foo => foo.Bar = null, options => options.WhenCalled(invocation => Assert.That(invocation.Arguments[0] is CorrectBarSubclass)));
    }

Rhino 3.5 / AAA Documentation 描述了如何对具有给定值的属性集设置期望值,但我只想检查值的类型。

如何断言属性集,特别是具有给定参数类型的属性集?


更新: 上面的例子过于简单了。我实际测试的是一个单独的状态类。这是“父对象”(具有状态的对象,在本例中为 Foo)可以处于的几种状态之一。我正在验证被测状态(称为 BarOne)是否正确地将 Foo.State 设置为 BarTwo 的实例是时候过渡状态了。

一个更清晰的例子(实施了公认的解决方案)是:

    [Test]
    public void BarOne_DoSomething_SetsNextState()
    {
        // Arrange
        Foo foo = MockRepository.GenerateMock<Foo>(); // Creates mock in Replay mode (what I want for AAA syntax).
        foo.Stub(x => x.CreateBarTwoState()).Return(new BarTwo(foo));
        BarOne bar = new BarOne(foo); // We are testing the BarOne state independently of Foo, that's why we mock Foo but instantiate BarOne.

        // Act
        bar.DoSomething();

        // Assert that DoSomething set Foo.Bar to an instance of BarTwo
        foo.AssertWasCalled(foo => foo.Bar = Arg<BarTwo>.Is.TypeOf);
    }

【问题讨论】:

  • 我理解它只是一个小例子,但期望 Bar 在这里被一个模拟对象调用是没有意义的。能否请您粘贴一个更完整的示例?
  • 好点 Grzenio,更新了我上面的问题。

标签: c# unit-testing nunit rhino-mocks


【解决方案1】:

大概是这样的:

[Test]
public void AddPlayer_GivesGameEnoughPlayersToStart_SetsNextState()
{
    // Arrange
    Foo foo = MockRepository.GenerateMock<Foo>(); // Creates mock in Replay mode (what I want for AAA syntax).
    foo.Expect(m => m.Bar = Arg<CorrectBarSubclass>.Is.TypeOf);
    // Act
    foo.DoSomething();
    //Assert
    foo.VerifyAllExpectations();
}

那是怎么回事..

我们将断言更改为 Expect。我发现这有点干净,而且期望允许我们更清楚地验证类型是什么。我们在说“期望 Bar 将设置为 CorrectBarSubclass 的实例。然后我们采取行动,并断言我们的期望得到了满足。

几件事:任何时候你模拟一个类,你有一个ExpectStub 调用必须是虚拟的或抽象的,所以在这种情况下,Bar 必须是虚拟的。通常最好模拟一个接口并测试一个类如何使用依赖项,而不是测试一个类如何使用自身(这通常表示过度测试或不正确的关注点分离)。

在您的情况下,甚至需要模拟吗?您只是使用一种有点复杂的语法来断言真实行为的结果,除了属性的设置器之外,没有什么是真正的模拟。有时,测试真实行为更容易,也更合适。为什么不这样做:

var foo = new Foo();
foo.DoSomething();
Assert.That(foo.Bar is CorrectBarSubclass);

【讨论】:

  • 谢谢——虽然我试过 Arg.Is.TypeOf,但问题是需要删除另一个方法(创建 CorrectBarSubclass 实例的方法)。这个例子很不稳定,因为它是对我的实际 Foo 类的过度简化。它使用状态模式,我正在测试一个单独的状态类,以确保它在类上设置下一个正确的状态。更新了原始问题以说明这一点。
【解决方案2】:

我遇到过类似的问题,我试图将谓词表达式存根到包含字符串的 Find-method(这当然是不可变的)。在我创建 testPredicate 之前没有成功,我将其传递给存根、实际 SUT 并最终断言。下面的代码有效。

    [Test()]
    public void Search_Apartment_With_Spesific_Address()
    {
        //ARRANGE
        var repositoryMock = MockRepository.GenerateMock<IApartmentRepository>();
        var notificationMock = MockRepository.GenerateMock<INotificationService>();
        var service = new ApartmentService(repositoryMock, notificationMock);
        var apartment = new List<Apartment> {new Apartment {Address = "Elm Street 2"}}.AsQueryable();

        Expression<Func<Apartment, bool>> testPredicate = a => a.Address == "Elm Street 2";
        repositoryMock.Stub(x => x.Find(testPredicate)).Return(apartment);

        //ACT
        service.Find(testPredicate);

        //ASSERT
        repositoryMock.AssertWasCalled(x => x.Find(testPredicate));
    }

编辑:此答案已修改并发送到更正的 IQueryable 存根问题。

【讨论】:

    猜你喜欢
    • 2016-06-21
    • 2021-12-16
    • 1970-01-01
    • 2019-11-03
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    相关资源
    最近更新 更多