14

I use NMock2, and I've drafted the following NMock classes to represent some common mock framework concepts:

  • Expect: this specifies what a mocked method should return and says that the call must occur or the test fails (when accompanied by a call to VerifyAllExpectationsHaveBeenMet()).

  • Stub: this specifies what a mocked method should return but cannot cause a test to fail.

So which should I do when?

Community
  • 1
  • 1
Jeff Sternal
  • 47,787
  • 8
  • 93
  • 120
  • Expect will return Nothing while Stub will return what you specify. both of them 'stub' the method once – zinking Nov 21 '13 at 09:40

3 Answers3

18

A lot of mocking frameworks are bringing the concepts of mocks & stubs closer & closer together to the point that they can be considered functionally almost the same. From a conceptual perspective however, I usually try to follow this convention:

  • Mock: Only when you are explicitly trying to verify the behaviour of the object under test (i.e. your test is saying that this object must call that object).
  • Stub: When you are trying to test some functionality/behaviour, but in order to get that working you need to rely on some external objects (i.e. your test is saying that this object must do something, but as a side effect, it may call that object)

This becomes clearer when you make sure that each of your unit tests only test one thing. Sure if you try to test everything in one test then you might as well Expect everything. But by only expecting the things that specific unit test is checking for, your code is much clearer because you can see at a glance what the purpose of the test is.

Another benefit of this is that you'll be slightly more insulated from change & get better error messages when a change causes a break. In other words if you subtley change some part of your implementation, your more likely to get only one test case breaking, which will show you exactly what's broken, rather than a whole suite of tests breaking & just creating noise.

Edit: It might be clearer based on a contrived example where a calculator object audits all additions to a database (in pseudo-code)...

public void CalculateShouldAddTwoNumbersCorrectly() {
    var auditDB = //Get mock object of Audit DB
    //Stub out the audit functionality...
    var calculator = new Calculator(auditDB);
    int result = calculator.Add(1, 2);
    //assert that result is 3
}

public void CalculateShouldAuditAddsToTheDatabase() {
    var auditDB = //Get mock object of Audit DB
    //Expect the audit functionality...
    var calculator = new Calculator(auditDB);
    int result = calculator.Add(1, 2);
    //verify that the audit was performed.
}

So in the first test case we're testing the functionality of the Add method & don't care whether an audit event occurs or not, but we happen to know that the calculator won't work with out an auditDB reference so we just stub it out to give us the minimum of functionality to get our specific test case working. In the second test we're specifically testing that when you do an Add, the audit event happens, so here we use expectations (notice that we don't even care what the result is, since that's not what we're testing).

Yes you could combine the two cases into one, & do expectations and assert that your result is 3, but then you're testing two cases in one unit test. This would make your tests more brittle (since there's a larger surface area of things that could change to break the test) and less clear (since when the merged test fails its not immediately obvious what the problem is.. is the addition not working, or is the audit not working?)

Alconja
  • 14,834
  • 3
  • 60
  • 61
  • I'm not sure how it is with other mocking frameworks, but with NMock, if you start checking one Expectation, you're on the hook for *all* external calls, which sometimes creates a crushing burden. I realize this requirement pushes us toward better design, but in many cases, I want to write unit tests for legacy code where I cannot afford to perform much refactoring in the time before I have to ship. – Jeff Sternal Jul 10 '09 at 01:19
  • 2
    Hmm... that does make a difference then. I've mainly used RhinoMocks, which allows you to Expect one method & then Stub others. My points still mostly stand (see my added example), but in your case, I guess you'll need to do all your expectation based testing (i.e. behaviour testing) in one test. – Alconja Jul 10 '09 at 01:28
  • Ack, I should have clarified (and might want to mention this in the body of my question): you can mix Expects and Stubs in NMock as well. The problem is that often I'd like to just specify one Expectation not even have to stub the rest (again, this is particularly true when I'm dealing with code that could use a good solid re-architecting - when there are numerous hidden layers of external calls). Oh, and +1. – Jeff Sternal Jul 10 '09 at 01:33
  • I'm not really familiar with NMock, but with RhinoMocks I'm pretty sure you if you generate a Stub object, you can still do Expectations on specific methods (treating it partially like a Mock object) leaving the other methods with the default stub implementations (i.e. returning null/false/0/etc). Sounds like that might give you the result you want... so one option may be to change mocking libraries. – Alconja Jul 10 '09 at 02:21
  • Okay..Okay. Explanation. – Arup Rakshit Sep 03 '14 at 06:51
5

"Expect actions, stub queries". If the call should change the state of the world outside the object under test, then make it an expectation--you care about how it gets called. If it's just a query, you can call it once or six times without changing the state of the system, then stub the call.

One more thing, notice that the distinction is between stubs and expectations, that is individual calls, not necessarily entire objects.

Steve Freeman
  • 2,707
  • 19
  • 14
1

Well... IMHO it can't be simpler: if your test is about ensuring your Presenter will call Save, do an Expect. if your test is about ensuring your Presenter will handle exception gracefully if Save throws up, do a Stub.

For more details, check out this podcast by Hanselman and Osherove (author of The Art Of Unit Testing)

Andriy Volkov
  • 18,653
  • 9
  • 68
  • 83
  • +1 for a good use case, though it is very narrow - I think the question could still be *quite* a bit simpler. – Jeff Sternal Jul 10 '09 at 01:17
  • Alright. If you insist I will baby-feed ya :) Unit-test should only test one thing. Never two. It should either test whether SUT (System Under Test) properly delegates some action to one of its dependencies. Or it should test whether SUT properly reacts to a result returned by a dependency. If first, use Mock. If second, use Stub. If in doubt, use Jack of Diamonds. – Andriy Volkov Jul 10 '09 at 01:36