Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Value of Behavior Verification

I've been reading up on (and experimenting with) several Java mocking APIs such as Mockito, EasyMock, JMock and PowerMock. I like each of them for different reasons, but have ultimately decided on Mockito. Please note though, that this is not a question about which framework to use - the question really applies to any mocking framework, although the solution will look different as the APIs are (obviously) different.

Like many things, you read the tutorials, you follow the examples, and you tinker around with a few code samples in a sandbox project. But then, when it comes time to actually use the thing, you start to choke - and that's where I am.

I really, really like the idea of mocking. And yes, I am aware of the complaints about mocking leading to "brittle" tests that are too heavily coupled with the classes under test. But until I come to such a realization myself, I really want to give mocking a chance to see if it can add some good value to my unit tests.

I'm now trying to actively use mocks in my unit tests. Mockito allows both stubbing and mocking. Let's say we have a Car object that has a getMaxSpeed() method. In Mockito, we could stub it like so:

Car mockCar = mock(Car.class);
when(mockCar.getMaxSpeed()).thenReturn(100.0);

This "stubs" the Car object to always return 100.0 as the max speed of our car.

My problem is that, after writing a handful of unit tests already...all I'm doing is stubbing my collaborators! I'm not using a single mock method (verify, etc.) available to me!

I realize that I'm stuck in a "stubbing state of mind" and I'm finding it impossible to break. All this reading, and all this excitement building up to using mocks in my unit testing and... I can't think of a single use case for behavior verification.

So I backed up and re-read Fowler's article and other BDD-style literatures, and still I'm just "not getting" the value of behavior verification for test double collaborators.

I know that I'm missing something, I'm just not sure of what. Could someone give me a concrete example (or even a set of examples!) using, say, this Car class, and demonstrate when a behavior-verifying unit test is favorable to a state-verifying test?

Thanks in advance for any nudges in the right direction!

like image 387
IAmYourFaja Avatar asked Dec 27 '11 17:12

IAmYourFaja


1 Answers

Well, if the object under test calls a collaborator with a computed value, and the test is supposed to test that the computation is correct, then verifying the mock colaborator is the right thing to do. Example:

private ResultDisplayer resultDisplayer;

public void add(int a, int b) {
    int sum = a + b; // trivial example, but the computation might be more complex
    displayer.display(sum);
}

Clearly, in this case, you'll have to mock the displayer, and verify that its display method has been called, with the value 5 if 2 and 3 are the arguments of the add method.

If all you do with your collaborators is call getters without arguments, or with arguments which are direct inputs of the tested method, then stubbing is probably sufficient, unless the code might get a value from two different collaborators and you want to verify that the appropriate collaborator has been called.

Example:

private Computer noTaxComputer;
private Computer taxComputer;

public BigDecimal computePrice(Client c, ShoppingCart cart) {
    if (client.isSubjectToTaxes()) {
        return taxComputer.compute(cart);
    }
    else {
        return noTaxComputer.compute(cart);
    }
}
like image 132
JB Nizet Avatar answered Sep 20 '22 05:09

JB Nizet