Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rhino Mocks - Stub .Expect vs .AssertWasCalled

Tags:

rhino-mocks

OK, I know there has been a lot of confusion over the new AAA syntax in Rhino Mocks, but I have to be honest, from what I have seen so far, I like. It reads better, and saves on some keystrokes.

Basically, I am testing a ListController which is going to basically be in charge of some lists of things :) I have created an interface which will eventually become the DAL, and this is of course being stubbed for now.

I had the following code:

(manager is the system under test, data is the stubbed data interface)

    [Fact]     public void list_count_queries_data()     {         data.Expect(x => x.ListCount(1));         manager.ListCount();         data.VerifyAllExpectations();     } 

The main aim of this test is to just ensure that the manager is actually querying the DAL. Note that the DAL is not actually even there, so there is no "real" value coming back..

However, this is failing since I need to change the expectation to have a return value, like:

        data.Expect(x => x.ListCount(1)).Return(1); 

This will then run fine, and the test will pass, however - what is confusing me is that at this point in time, the return value means nothing. I can change it to 100, 50, 42, whatever and the test will always pass?

This makes me nervous, because a test should be explicit and should totally fail if the expected conditions are not met right?

If I change the test to (the "1" is the expected ID the count is linked to):

    [Fact]     public void list_count_queries_data()     {         manager.ListCount();         data.AssertWasCalled(x => x.ListCount(1));     } 

It all passes fine, and if I switch the test on it's head to AssertWasNotCalled, it fails as expected.. I also think it reads a lot better, is clearer about what is being tested and most importantly PASSES and FAILS as expected!

So, am I missing something in the first code example? What are your thoughts on making assertions on stubs? (there was some interesting discussion here, I personally liked this response.

like image 741
Rob Cooper Avatar asked Jan 25 '09 16:01

Rob Cooper


1 Answers

What is your test trying to achieve?

What behaviour or state are you verifying? Specifically, are you verifying that the collaborator (data) is having its ListCount method called (interaction based testing), or do you just want to make ListCount return a canned value to drive the class under test while verifying the result elsewhere (traditional state based testing)?

If you want set an expectation, use a mock and an expectation: Use MockRepository.CreateMock<IMyInterface>() and myMock.Expect(x => x.ListCount())

If you want to stub a method, use MockRepository.CreateStub<IMyInterface>() and myStub.Stub(x => x.ListCount()).

(aside: I know you can use stub.AssertWasCalled() to achieve much the same thing as mock.Expect and with arguably better reading syntax, but I'm just drilling into the difference between mocks & stubs).

Roy Osherove has a very nice explanation of mocks and stubs.

Please post more code!

We need a complete picture of how you're creating the stub (or mock) and how the result is used with respect to the class under test. Does ListCount have an input parameter? If so, what does it represent? Do you care if it was called with a certain value? Do you care if ListCount returns a certain value?

As Simon Laroche pointed out, if the Manager is not actually doing anything with the mocked/stubbed return value of ListCount, then the test won't pass or fail because of it. All the test would expect is that the mocked/stubbed method is called -- nothing more.

To better understand the problem, consider three pieces of information and you will soon figure this out:

  1. What is being tested
  2. In what situation?
  3. What is the expected result?

Compare: Interaction based testing with mocks. The call on the mock is the test.

[Test] public void calling_ListCount_calls_ListCount_on_DAL() {    // Arrange    var dalMock = MockRepository.Mock<IDAL>();    var dalMock.Expect(x => x.ListCount()).Returns(1);    var manager = new Manager(dalMock);     // Act    manager.ListCount();     // Assert -- Test is 100% interaction based    dalMock.VerifyAllExpectations();    } 

State based testing with a stub. The stub drives the test, but is not a part of the expectation.

[Test] public void calling_ListCount_returns_same_count_as_DAL() {    // Arrange    var dalStub = MockRepository.Stub<IDAL>();    var dalStub.Stub(x => x.ListCount()).Returns(1);    var manager = new Manager(dalMock);     // Act    int listCount = manager.ListCount();     // Assert -- Test is 100% state based    Assert.That(listCount, Is.EqualTo(1),        "count should've been identical to the one returned by the dal!"); } 

I personally favour state-based testing where at all possible, though interaction based testing is often required for APIs that are designed with Tell, Don't Ask in mind, as you won't have any exposed state to verify against!

API Confusion. Mocks ain't stubs. Or are they?

The distinction between a mock and a stub in rhino mocks is muddled. Traditionally, stubs aren't meant to have expectations -- so if your test double didn't have its method called, this wouldn't directly cause the test to fail.

... However, the Rhino Mocks API is powerful, but confusing as it lets you set expectations on stubs which, to me, goes against the accepted terminology. I don't think much of the terminology, either, mind. It'd be better if the distinction was eliminated and the methods called on the test double set the role, in my opinion.

like image 51
Mark Simpson Avatar answered Sep 23 '22 13:09

Mark Simpson