views:

99

answers:

3

I have started using moq for mocking. Can someone explain me the concept of strict and non-strict mocks? How can they can be used in moq?

edit: in which scenario do we use which type of mock?

+2  A: 

I'm not sure about moq specifically, but here's how strict mocks work in Rhino. I declare that I expect a call to foo.Bar on my object foo:

foo.Expect(f => f.Bar()).Returns(5);

If the calling code does

foo.Bar();

then I'm fine because the expectations are exactly met.

However, if the calling code is:

foo.Quux(12);
foo.Bar();

then my expectation failed because I did not explicitly expect a call to foo.Quux.

To summarize, a strict mock will fail immediately if anything differs from the expectations. On the other hand, a non-strict mock (or a stub) will gladly "ignore" the call to foo.Quux and it should return a default(T) for the return type T of foo.Quux.

The creator of Rhino recommends that you avoid strict mocks (and prefer stubs) because you generally don't want your test to fail when receiving an unexpected call as above. It makes refactoring your code much more difficult when you have to fix dozens of test that relied on the exact original behavior.

Mark Rushakoff
where have you specified it is a strict mock?
Sandbox
@Sandbox: You would specify strict or non-strict in [the `Mock` constructor that takes a `MockBehavior` argument](http://www.clariusconsulting.net/labs/moq/html/DD4BEE30.htm). The default behavior (when not specifying the `MockBehavior`) appears to be non-strict (they call it "loose").
Mark Rushakoff
A: 

Ever come across Given / When / Then?

  • Given a context
  • When I perform some events
  • Then an outcome should occur

This pattern appears in BDD's scenarios, and is also relevant for unit tests.

If you're setting up context, you're going to use the information which that context provides. For instance, if you're looking up something by Id, that's context. If it doesn't exist, the test won't run. In this case, you want to use a NiceMock or a Stub or whatever - Moq's default way of running.

If you want to verify an outcome, you can use Moq's verify. In this case, you want to record the relevant interactions. Fortunately, this is also Moq's default way of running. It won't complain if something happens that you weren't interested in for that test.

StrictMock is there for when you want no unexpected interactions to occur. It's how old-style mocking frameworks used to run. If you're doing BDD-style examples, you probably won't want this. It has a tendency to make tests a bit brittle and harder to read than if you separate the aspects of behaviour you're interested in. You have to set up expectations for both the context and the outcome, for all outcomes which will occur, regardless of whether they're of interest or not.

For instance, if you're testing a controller and mocking out both your validator and your repository, and you want to verify that you've saved your object, with a strict mock you also have to verify that you've validated the object first. I prefer to see those two aspects of behaviour in separate examples, because it makes it easier for me to understand the value and behaviour of the controller.

In the last four years I haven't found a single example which required the use of a strict mock - either it was an outcome I wanted to verify (even if I verify the number of times it's called) or a context for which I can tell if I respond correctly to the information provided. So in answer to your question:

  • non-strict mock: usually
  • strict mock: preferably never

NB: I am strongly biased towards BDD, so hard-core TDDers may disagree with me, and it will be right for the way that they are working.

Lunivore
A: 

Here's a good article.
I usually end up having something like this

public class TestThis {

    private final Collaborator1 collaborator1;
    private final Collaborator2 collaborator2;
    private final Collaborator2 collaborator3;

    TestThis(Collaborator1 collaborator1, Collaborator2 collaborator2, Collaborator3 collaborator3) {
        this.collaborator1 = collaborator1;
        this.collaborator2 = collaborator2;
        this.collaborator3 = collaborator3;
    }

    public Login login(String username) {
        User user = collaborator1.getUser(username);
        collaborator2.notify(user);
        return collaborator3.login(user);
    }

}

...and I use Strict mocks for the 3 collaborators to test login(username). I don't see how Strict Mocks should never be used.

al nik