The short version
Whenever you want to accomplish both task 1 and task 2, don’t end up with a class that does task 1 and then uses a collaborator class to do task 2. Instead, use one class to do the the orchestration of two collaborator classes, one for each task.
The longer version
Some things are hard to test. Sometimes this is because, well … er … some things are hard to test. But sometimes, sometimes this is a sign that should push the design and code in a new direction. Not only to make the tests easier to write, but hopefully also to make the code more elegant.
One example of the latter case is when I find myself struggling with testing a class that both uses one or many collaborators, and uses the output from the collaborators to execute some business logic in the class itself. Those tests will be hard to follow at best, because the tests both have to handle the interaction between the mocked collaborator/s and the class’ own business logic, which makes for cluttered test code.
Because I have found myself in this situation quite a few times I have started to apply an almost mechanical solution. It’s really not much more than thinking of Separation of Concerns (SoC) or the Single Responsibility Principle (SRP), maybe with the small tweak of understanding that orchestration of collaborators is a concern/responsibility of its own. Thus, a class that is both orchestrating collaborators and carrying out business logic, is having one too many concerns and responsibilities, and is breaking SoC/SRP. The solution is obvious, let classes carry out some business logic, or orchestrate other classes. This single change gives you:
- Classes that are much easier to test. Either you’ll test a class’ abilities to carry out a piece of business logic, or you’ll tests a class’ abilities to orchestrate other classes, not both.
- The design gets cleaner and more elegant. You can now think of (and actually draw) the program flow as a tree with an orchestration class as a parent node to new orchestration classes or,as leaf nodes, single business task classes.