During the development of Kaffeesatz, a tool to take a Git Repository and get an overview on which files were edited the most, to identify which files could be candidates for a refactoring or are suspected to violate the Single Responsibility Principle, I wanted to show the user a visual cue on the progress of going through the history of the repository before he is able to see the report.
I chose to display a progress bar in the terminal which will look as follows in the case where 30% of the report is completed
To verify what is printed to stdout we can use the following test
Additionally one should not forget to reset the stdout redirection in the tearDown
method.
Done. The progress bar display is tested and everything seems fine.
But… The tests above are integration-tests which are testing the workings of stdout multiple times although we should probably trust the correctness of Java libraries. We also do not have any idea DisplayProgressBar
has a dependency on stdout. Usually dependencies of a class are made visible by passing them into the constructor of the class. Which, as a result, allows to replace the dependency during testing or, if its an interface, with a class implementing the interface. This does not happen in the above case. The class violates the Dependency Inversion Principle.
Having a look at Wikipedia we can define the Dependency Inversion Principle as follows:
High-level modules should not depend on low-level modules. Both should depend on abstractions.
High-level modules in this case is the business logic of giving the user feedback on the progress of an operation. Low-level modules here is the how we provide the progress to the user.
The current implementation of DisplayProgressBar
violates the principle because the use case of “providing progress to the user” depends on the delivery mechanism of displaying the progress bar. In our case the delivery mechanism is stdout.
What if we want to replace the delivery mechanism and instead display the progress bar as HTML in a web-app? In that case we would have to modify the class containing the use-case and rewrite the test.
Let’s try to decouple the use case from the delivery mechanism by putting an interface in-between.
Let’s create an implementation of the Display
interface.
We can now make do with a single integration test which tests if something can be printed at all.
Thus we have created an abstraction for writing to stdout. The correct usage of the interface in the implementation of the progress bar can be tested by using a Spy. Using the mocking framework Mockito it will look as follows
Quite concise and less opportunity for errors. The dependency on a Display
becomes visible and the Dependency Inversion Principle is not violated anymore.