Let's take a look at a simple example, that will try to show the challenges that we may face:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class HardToTestClass { | |
public Double calculateDiscount(String customerName, Integer amount) { | |
Double discount = 0.0; | |
if (amount > 10 || CustomerService.isImportantCustomer(customerName)) { | |
discount = 25.0; | |
} | |
return discount; | |
} | |
} |
The problem hides in a static method call CustomerService.isImportantCustomer(). In the old code we can see a lot of static methods. Let's say that the one in our example is calling the database.
We need to mock it in order to write a proper unit test.
First of all, we will extract the static call to a separate method:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class HardToTestClass { | |
public Double calculateDiscount(String customerName, Integer amount) { | |
Double discount = 0.0; | |
if (amount > 10 || isImportantCustomer(customerName)) { | |
discount = 25.0; | |
} | |
return discount; | |
} | |
boolean isImportantCustomer(String customerName) { | |
return CustomerService.isImportantCustomer(customerName); | |
} | |
} |
If we declare our tested class as a spy, we can mock its method the same way as with standard mocks. The test for our class could look like:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@RunWith(MockitoJUnitRunner.class) | |
public class HardToTestClassTest { | |
private static final double ZERO_DISCOUNT = 0.0; | |
@Spy | |
private HardToTestClass hardToTestClass; | |
private String customerName = "Neal Stephenson"; | |
private Integer lowAmount = 1; | |
@Test | |
public void shouldReturnZeroDiscountIfAmountIsLowAndCustomerIsNotImportantOne() { | |
// given | |
given(hardToTestClass.isImportantCustomer(customerName)).willReturn(false); | |
// when | |
Double result = hardToTestClass.calculateDiscount(customerName, lowAmount); | |
// then | |
assertThat(result, is(ZERO_DISCOUNT)); | |
} | |
} |