The MathApplication
is dependent on a CalculatorService
which provides - as its name suggests - service for calculations.
However, in unit tests, you want to test only the class under test (MathApplication
), so you want to replace all the dependencies by your own implementation over which you have full control. For this purpose you use the mock.
calcService = EasyMock.createMock(CalculatorService.class);
Dependency injection is a pattern which "injects" the object you are dependent on into the main object.
There are three approaches to getting instances of objects you class depends on.
public class MathApplication {
// I need an instance of CalculatorService inside the code of MathApplication
...
}
1: Instantiate the object inside the code of MathApplication
(it doesn't matter if the calculatorService
is local or a class attribute). This is not very recommendable way.
public double subtract(double a, double b) {
CalculatorService calculatorService = new SomeFastCalculatorService();
return calculatorService.subtract(a, b);
}
2: Delegate the task of instantiation to an external provider, called factory:
public double subtract(double a, double b) {
CalculatorService calculatorService = CalculatorServiceFactory.getInstance();
return calculatorService.subtract(a, b);
}
3: Let someone from outside inject the instance by providing an injection point, either via constructor of via a setter method.
It is used in general for building the "dependency tree" of you whole application (usually using frameworks such as Spring Dependency Injection or JavaEE CDI). Here it used to inject your mock object into the class under test:
mathApplication.setCalculatorService(calcService);
Later on, in your @Test
method, you exactly set the behaviour of your mock object.
EasyMock.expect(calcService.add(20.0, 10.0)).andReturn(30.0);
to be read as "when calcService.add()
is called with 20 and 10, give 30".
And at the end you:
- Test if your tested method returns what is expected -
assertXXX()
- Test if the calcService has been used -
verify()
Btw, the code
Assert.assertEquals(mathApplication.subtract(20.0, 10.0), 10.0, 0);
contains an error - look at the documentation. Correctly it should be
Assert.assertEquals(10.0, mathApplication.subtract(20.0, 10.0), 0);
It works almost the same, just you will get more proper error message if the test doesn't work:
Assertion error - expected 10.0, but was 11.0.
And anyway, it would be better readable if written as:
double expected = 30.0;
double actual = mathApplication.subtract(20.0, 10.0);
Assert.assertEquals(expected, actual, 0.0000000001); // never expect exact floating point result
And why you should interface: it's a good practice :) It's easier for the frameworks to mock an interface than a class (and some mock frameworks even cannot mock a class). And it leads you in learning to separate an interface from its implementation and write better testable classes.