If your Ruby unit tests are failing because you change the signature of a method and all your mock expectations fail, you might have a case of Overspecified Software. To fix this problem, make your test require only the parameters that are significant. To quote Gerard Meszaros, "If a value is not important to a test, it's important that it not be in the test."
For example, imagine you had a test which took an options Hash as a parameter. You might have an expectation like this:
processor.expects(:order).with(:payment => :credit_card, :delivery => :express, :group => :separate)
Unless your test is verifying that all of these parameters are set correctly, it might be better to change your tests so that each test verifies only the parameters that are important. In this post, I'll describe how to do this with Mocha, but Flex Mock also provides similar features.
Mocha provides a flexible syntax to match parameters of expectations. For example, if you wanted to check that a given key was present, and ignore the rest of the arguments, you could say:
processor.expects(:order).with(has_key(:payment))
If you are interested in both the key and value, you could use has_entry, or the alternate has_entries:
processor.expects(:order).with(has_entry(:payment => :credit_card))
If you just wanted to make sure something was NOT present, you can use the Not operation to invert the condition:
processor.expects(:order).with(Not(has_key(:emergency_order)))
Or specify any number of conditions using the any_of condition.
processor.expects(:order).with(any_of(includes(:delivery), has_key(:shipping)))
Mocha provides many more variations, see the Mocha::ParameterMatchers RDoc for more possibilities.
By combining these parameter matchers, you can make tests that are more expressive about the arguments they care about and avoid unrelated test failures when you make a harmless change to your code.
Comments
You can follow this conversation by subscribing to the comment feed for this post.