There is a discussion in the spanish TDD group about whether it is good or bad, when you have a stub object, to return a different value depending on the input arguments of the method. I don't think it's the right thing to do because, normally, when a stub object cares about the input arguments in its method calls it's because it should not be a stub object, it should be a mock object. Let me explain it with an example:
The payment gateway is a stub that returns true when user_has_funds is called with an input argument of 50.
If we look carefully at the test, what we are really doing is testing more than one behavior. First, we're asserting that a user can buy stuff if she has sufficient funds. Second, we are expecting that the payment gateway is called with the right amount.
So, if it is an expectation, why don't we use a mock instead of a stub? We're mixing the concepts of mock and stub and, as a consequence, we're testing more than one thing.We're breaking the single responsibility principle.
Steve Freeman and Nat Pryce, authors of the great Growing objects oriented software, guided by tests, recommend to follow a simple rule of thumb, "specify exactly what you want to happen and no more". If we listen to them (and we should!), those are the resulting tests:
The first test specifies the relationship between the order and the payment gateway (The message protocol). It uses a mock object to replace the gateway payment object and it expects a call at user_has_funds method with the order amount as an input argument. We want to know that the payment gateway is going to be called with the right amount, so we are interested in its input argument (which is right when mocking). The second one specifies the behavior of the order when the user has funds, and I don't really care about how the order interacts with the payment gateway. I just want to know that the user has sufficient funds. That's why, in this case, we use a stub.
What I like about the new tests is that, if we change the order behavior by adding some taxes to the product price, the second test is not going to break (we still confirm the order if the payment gateway says that the user has funds, nothing has changed in that specification). Only the first one would be red (and for the right cause, we've changed exactly that specification).
What do you think?
PS: I know that, in RSpec:mocks, stub() is an alias for mock() and I don't like it very much :P
Mostrando entradas con la etiqueta mocks. Mostrar todas las entradas
Mostrando entradas con la etiqueta mocks. Mostrar todas las entradas
miércoles, 9 de febrero de 2011
Suscribirse a:
Entradas (Atom)