Welcome to Part 5 of this review of the Pluralsight course Introduction to Testing in Java by Richard Warburton.
Richard defines a dependency as:
“A relationship between two components where the functionality of one component relies on another component”
As an example of this we have a sales report with three components: Report, AnalysisService and CsvRepository
Report is dependent on the AnalysisService, and AnalysisService is dependent on the CsvRepository.
Richard explains there are two problems with this:
1. Lack of isolation
This is a way to resolve the coupling issues that the sales report has. Richard says it’s
“A $20 term for a 20 cent concept”
We look at constructor injection in this module, and this is the most common way of doing dependency injection.
Dependency Injection (Live Coding)
We see the Sales Report application and Richard talks us through its classes:
We refactor this to use constructor injection, and create a SalesRepository interface which CsvSalesRepository implements.
The code still behaves the same as before, but we now have better separation of concerns, looser coupling, and the code is easier to test.
We use test doubles instead of the real implementations that our class under test is dependent on. There are several types on Test Double:
– Fake: working implementation but much simpler than a real one
– Stub: a ready-made answer to method calls
– Mock: Tests the interactions with the object
See Martin Fowler’s classic article mocks aren’t stubs
Also see Alex Zhukovich’s Android testing: Mockito and Robolectric
Test Doubles (Live Coding)
The code here is Java 8, so if you’re confused see the “What’s New in Java 8” course.
The first test is
shouldAggregateStoreSales, and we use our own hand-made stubRepo as our SalesRepository stub.
However Richard says as things get more complicated it’s better for as to use a library such as Mockito.
We refactor this test to use Mockito and first find it returns an empty list as a stub, which isn’t what we want.
We need to tell Mockito the value we want for our stub:
We can make this code terser by right clicking on the Mockito methods by adding static imports.
For example we can right click on
Mockito.mock and choose
“Add static import for ‘org.mockito.Mockito.mock'”
Mockito also has a verify method and Richard shows us we can use this to verify our tallyStores method has called loadSales:
Appendix 1: Spring
This is a brief look at the Spring DI framework. Richard says it’s “not a simple beast” and if you need to learn it in detail you should watch the Spring Fundamentals course by Bryan Hansen.
The advantage over using Spring over hand-written dependency injection is the Spring framework offers a lot of functionality.
Richard says it’s overkill for simple applications but useful for more complex ones and is the most commonly used DI framework for Java.
Appendix 2: Guice
Guice (pronounced ‘Juice’) is a lightweight DI framework for Java written by Google.
It has good documentation available on Github.
Again it doesn’t do anything that we can’t do by hand, but can simplify Inversion of Control for us once we’ve learnt it by reducing boilerplate code.
We use modules here, which are like recipes of telling Guice how to build an object graph. We also use a DSL syntax for binding classes and instances.