5 ms·
Cute, but even as terse as this comment is its sentiment is incorrect. Mocks, almost by their very nature, encourage coupling. Ask yourself the question "What
by revscat 12y ago
Cute, but even as terse as this comment is its sentiment is incorrect.
Mocks, almost by their very nature, encourage coupling. Ask yourself the question "What tends to get mocked? " Answer: Objects which are difficult and/or heavy to instantiate, but which are outside of your direct control and cannot be changed, e.g.: database connections, network sockets, etc.
So when you want to write tests around this you are almost forced to mock them out. So you instantiate those classes (as mocks) in your test class, so that the code under test. There are now two references to that class: one in the test, and one in the code being tested.
This is coupling. QED.
- tomstuart 12y ago> Ask yourself the question "What tends to get mocked?" Answer: every collaborator of the object under test, so that only the tested object is actually having its implementation exercised. All other objects that it needs to talk to — database connections, network sockets, or whatever — are replaced with mocks, and the test subject’s interactions with those mocks are verified, so that a) we have confidence that the tested object is interacting with its collaborators in the expected way, and b) the test itself doesn’t depend at all on the actual behaviour of those collaborators’ implementations, which behaviour should be explicitly exercised elsewhere. That’s the opposite of coupling. I don’t understand where your answer comes from or what it means.
- mpdehaan2 12y agoI view this as definitely enforcing coupling. The issue is that you should want to make it very easy to change the API signature of internal components. Mock objects can tend to reinforce internal coding choices when things that are not a public interface, or a service boundary, are mocked out. If you're mocking at this level, there is a potential for refactoring of intra-class API contracts to become much harder to change. Thus, it would be better IMHO to mock out only meaningful service boundaries, and concentrate testing at the public contracts. You can still get very strong coverage, but you're just thinking about a different level of inputs.
- ollysb 12y agoThe point more accurately is that coupling to the interface used to communicate with your collaborator I.e. If you were to refactor the way that the test object communicates with it's collaborator (without changing it's external behaviour) you are now forced to update the mocks. If the collaborator is only used within your test object and nowhere else in your system the communication between them doesn't need to be pinned down, the test should just test both of them at the same time. This is the difference between a white box test (where your mocking has to expose implementation details) and blackbox testing (where you can refactor without breaking tests).
- emsy 12y agoDo you always hit the real database and network when you test? Because what you describe would also rule out stubs and fakes.
- Consultant32452 12y agoActually, my answer to "What tends to get mocked?" is quite different from yours. My answer is "Everything that is not what is currently being tested." So if I'm testing method Foo.bar, all of the method calls that leave Foo.bar are mocked. If Foo.bar calls A.b(), A will be mocked as its functionality is not currently under test. The only real exception is if A.b() is a trivial implementation and I don't already have A mocked for some other reason. If A.b() is a setter/getter, for example, I might not mock it.
- stouset 12y agoMocking "everything that is not what is currently being tested" is tautological. Mocking and stunning in the manner you describe makes tests extremely dependent upon the current implementation. In fact, it inverts the relationship your tests should have with your development process. Tests should allow you to refactor without breaking tests, and tests should break when APIs you call change in incompatible ways. These are the two primary long-term benefits that tests offer. Stubbing and mocking all of their internals causes tests to break when you change internal implementation (library Foo was switched to library Bar, but Foo is mocked and has a different API than Bar). It also causes tests not to break when the Foo API is incompatibly changed by another developer.
- Consultant32452 12y agoTests are generally for making sure your code appropriately handles cases where Foo behaves a certain way. That could be returning a certain value or throwing an exception, whatever types of branches you might have. Foo's implementation doesn't matter, therefore it gets mocked. If Bar doesn't, for example, throw the same exceptions, you've changed your method behavior and it makes sense to also update your tests/mocks.