I've been reading up on Mocks and Stubs, their differences and uses. I'm still a bit confused, but I think I've got the jist of it.
Now I'm wondering about applications. I can see the use in creating "fake" objects in testing scenarios where the actual objects are too complicated to haul around to test one aspect.
But let's consider my application: I'm working on a computational geometry library. Our library defines points, lines, linesegments, vectors, polygons, and polyhedra, along with a bunch of other objects and all the usual geometric operations. Any given object is stored as a list of points or directions, or lower level objects. But none of these objects takes more than a few milliseconds to generate.
When I'm testing this library, does it make sense to use Mocks/Stubs anywhere?
Right now we just use particular test cases. We're calling them stubs, but I don't think they meet the technical definition of a stub. What do you think better vocab for that would be? "TestCases"? "Examples"?
SourceCode: https://bitbucket.org/Clearspan/geometry-class-library/src
Edit: Note that we're striving for immutability in all our geometry objects, so it only makes sense to test the results of operations, but not state changes to the initial objects.
The fundamental difference between mock and stub is that mock can make your test fail. Stub can't. Stub is used to guarantee correct program flow. It is never part of assert.
Note that mock can also be used to guarantee flow. In other words, every mock is also a stub, and stub is never a mock. Because of such overlapping responsibilities nowadays you don't see much distinction between mock and stub and framework designers go for more general terms (like fake, substitute or catch-all mock).
This realization (mock - assert, stub - flow) helps us narrow down some usage scenarios. To start with the easier one...
Mock
As I mentioned mocks are used in asserts. When the expected behavior of your component is that it should talk to this other component - use mock. All those
can be only tested by asking "Did it call
ScheduleJob
with such and such parameters?" This is where you go for mock. Usually this will be mock's only usage scenario.Stub
With stub it's a bit different. Whether to use stub or not is a design question. Once you follow regular loosely coupled, dependency injection-based design, eventually you will end up with a lot of interfaces.
Now, when in test, how do return value from interface? You either stub it or use real implementation. Each approach has its pros and cons:
Angle
class changesCoordinateSystem
might fail... Is such behavior desirable or not?Is it? Which one to use? Both! It all depends on...
Unit of work
We arrived at final and the actual part of the problem. What is the scope of your unit test? What is the unit? Can
CoordinateSystem
be detached from its inner workings and dependencies (Angle
,Point
,Line
) and can they be stubbed? Or more importantly, should they be?You always need to identify what your unit is. Is it
CoordinateSystem
alone or perhapsAngle
,Line
andPoint
play important part of it? In many, many cases, the unit will be formed by both method and its surrounding ecosystem, including domain objects, helper classes, extensions or sometimes even other methods and other classes.Naturally, you can separate them and stub all the way around but then... is it really your unit?