Rhino Mocks: AAA Synax: Assert property was set wi

2019-07-14 05:18发布

问题:

I am trying to assert that a property in a mock object was set with a given type. The property has an abstract type and is set with one of a number of concrete types.

This is what I'm trying to do, and it's always passing the test regardless of the value that Foo.DoSomething() sets Foo.Bar with:

    [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)));
    }

The Rhino 3.5 / AAA Documentation describes how to set expectations on property sets having a given value, but I just want to check the type of the value.

How does one assert on a property set, specifically on a property set having a given parameter type?


Update: The example above is oversimplified. What I'm actually testing is an individual state class. It's one of several states that a "parent object" (the object having the state, Foo in this case) can be in. I was verifying that the state under test (call it BarOne) correctly set Foo.State to an instance of BarTwo when it was time to transition states.

A clearer example (with the accepted solution implemented) would be:

    [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);
    }

回答1:

Perhaps something like this:

[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();
}

So what's going on..

We changed the assertion to be an Expect. I find this a little bit cleaner, also the expectation allows us a cleaner verification of what the type is. We are Saying "Expect that Bar will be set to an instance of CorrectBarSubclass. Then we Act, and we assert that our expectation was met.

Couple of things: Any time you Mock a class, anything you have an Expect or Stub call on must be virtual or abstract, so in this case, Bar must be virtual. It's usually always better to mock an interface and test how a class uses a dependency, rather than testing how a class uses itself (that usually is an indication of over-testing, or incorrect separation of concerns).

In your case, is a mock even required? You are just using a somewhat complicated syntax to assert the result of a real behavior, nothing is really mocked other than the setter of a property. Sometimes it's just easier, and more appropriate, to test real behaviors. Why not do something like this:

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


回答2:

I've had similar problem where I tried to stub predicate expression to Find-method which contains string (which is immutable of course). No success until I've create testPredicate which I pass to stub, actual SUT and finally to assert. Below code works.

    [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));
    }

EDIT: this answer was mended and sended to correct IQueryable Stub-question.