Share via


I don't like Mock objects

When looking at BDD and TDD examples it is very common to see the use of mock objects in the code. This however strikes me as a little bit strange since I think you should use stubs and not mocks when working with BDD/TDD. A mock is basically a stub with the added knowledge that a mock object knows how it is expected to be used. In my opinion this fact disturbs the focus when  applying BDD/TDD. Additionally I think maintainability is decreased since the tests will now have a dependency on implementation internals and you risk having to change your test not because the API has changed but how things are done internally.

Let me explain what I mean with an example. Consider a data object used to handle transactions and the ability to read and modify the amount money on a given bank account. Now assume this data object is used as a parameter to a transfer method that is used to transfer funds between two accounts. One way to implement the transfer method could be:

  1. Start a transaction.
  2. Get amount from the to-account.
  3. Get amount from the from-account.
  4. Set new account amounts for both involved accounts.
  5. Check that the from-account does not have a negative balance.
  6. End the transaction.

From a maintainability point of view I think mocking the data object will be risky since the mock will verify that the correct number of calls are made in the correct order. It wouldn't surprise me if we some day saw a new transfer implementation looking something like this:

  1. Start a transaction.
  2. Get amount from the from-account.
  3. Check that the amount is enough.
  4. Get amount from the to-account.
  5. Set new account amounts for both involved accounts.
  6. End the transaction.

The example may seem a little far-fetched but still I think it points toward a maintainability risk involved when using a mock. But OK, let's assume that maintainability will not be a problem. We're still shifting focus from what is important I think. As soon as a mock is involved when I write my test/scenario I do not only have to think about the behavior I expect. I must also think about how my mock will be used since that may or may not affect my test code. Using stubs instead of mocks will reduce that focus shift since stubs are just doing what they're told without regard of context.

Sure one might argue that using stubs will also involve having to think about how the stub is used. That is true but without the risk of having order or number of calls to the stub mess up your test/scenario setup. And the less time you spend on thinking about setup and the more you spend on defining behavior, the better I think. And thinking about behavior of internals and/or dependent objects should just be kept to an absolute minimum if you ask me.

Comments

  • Anonymous
    May 24, 2008
    Yea... I tent to agree that you SHOULD use stubs instead... good point!

  • Anonymous
    October 12, 2008
    First of all I must remind you that I don't like mocks and mocks aren't stubs . But recently I read a

  • Anonymous
    October 13, 2008
    The comment has been removed

  • Anonymous
    October 13, 2008
    Since I'm not a fan of mocks I guess my prayers have been heard. Microsoft Research will soon release

  • Anonymous
    October 15, 2008
    @Keith: Sure, I agree that verifying order is optional and something you should not do. Still that is in most beginner examples I've seen so beginners tend do do that and sooner or later realize that is bad. I guess we can agree on disagreeing however. You think it is a good thing to shift focus from verifying calculation is correct to verifying calculation is implemented correctly. I think the opposite. Looking at it from a BDD perspective where you typically work "outside-in" (and using the example above) you would start with something like a service object that can be used to perform a number of services. One service is "transfer money". Being strict here - the only thing I can say about that method is that it should reduce one account's balance with the same ammount that is added to the other account. If I at this point think too much about the internal implementation details of this method I might end up with an interface that reflects the underlying implementation rather than an interface of what I want to do. In this simple example this may sound like a ridiculus statement since there is not many ways we can implement this correctly. But my point is that we should try to not think about implementation when writing the test/spec. And using mocks forrces us to do so. But I can however agree that mocks makes it harder to write bad tests where you fake to much (for example if we just fake the accounts and return the new balance whatever the test expects). But since we don't know in what context the mock is called I guess we can do the same thing there (calling remove first and commiting it and then calling add on the other account). Whatever type of object you choose good tests will mean having a number of tests working together in order to verify the correct behavior.

  • Anonymous
    October 18, 2008
    "start with something like a service object that can be used to perform a number of services. One service is 'transfer money'" So, that's an illuminating difference: I don't think I would start with that. It seems to me like a premature assignment of responsibilities. If BDD is to mean anything in particular (and it's not clear that it does) then I would understand it to mean structuring the system in a way closely bound to the user/customer's idea of their domain. I would be surprised to learn that the users in this world of accounts and payment would think first of any sort of "service object". That strikes me as very much an implementer's concept. I absolutely wold want to capture a functional test that gave examples of accounts and payments and new balances. Such a test indeed should say nothing whatever about how the post-condition might be achieved. And separately from that I would, when designing the interaction of the objects that fulfil that contract, and when assigning responsibilities to them, want unit tests that talk about those things. Mocks allow that in a way that assertions and stubs just don't. This approach has a surprisingly large impact on design thinking. Mocks as we have them today in jMock and such were invented to help answer the question: How would you unit test objects that had no setters or getters? Getterless code is hard to get to if your tests have to interrogate objects from the outside to see if post-conditions have been met. And yet it turns out to have lots of desirable properties. This is the real advantage of using Mocks for me: within the context of TDD they open the door to a design discipline based on roles and interactions rather than state.

  • Anonymous
    October 21, 2008
    The comment has been removed

  • Anonymous
    October 22, 2008
    The day started with Ken Schwaber talking on the topic: It is not Scrum if... Basically he tried to correct