DEV Community

Gabriel N Voicu
Gabriel N Voicu

Posted on • Edited on

Jumpstart Testing with Mockito and JUnit5

In this article, we will see JUnit and Mockito in action using 2 Java components, a service class, and a repository class.

We will start by creating the classes and then write tests in different ways to use concepts like, assert, verify, check for thrown exception, ArgumentMatcher and ArgumentCaptor. At last, we will create cleaner tests by extracting the duplicated code and even use Mockito annotations. We will not focus on having 100% code coverage.

Code under test
DataRepository.java

public interface DataRepository { int[] retrieveAllData(); int getStoredSumById(int id); void save(Object o); } 
Enter fullscreen mode Exit fullscreen mode

DataService.java

public interface DataService { int calculateSum(); void setDataRepository(DataRepository dataRepository); int calculateNewSum(int id); void save(Data o); } 
Enter fullscreen mode Exit fullscreen mode

DataServiceImpl.java

public class DataServiceImpl implements DataService { private DataRepository dataRepository; public void setDataRepository(DataRepository dataRepository) { this.dataRepository = dataRepository; } public int calculateSum(){ int sum = 0; for(int value : dataRepository.retrieveAllData()){ sum += value; } return sum; } public int calculateNewSum(int id){ int sum = dataRepository.getStoredSumById(id); return sum + sum; } public void save(Data o){ o = new Data(o.getName().toUpperCase()); dataRepository.save(o); } } 
Enter fullscreen mode Exit fullscreen mode

Data.java

public class Data { private String name; // constructors, getters and setters } 
Enter fullscreen mode Exit fullscreen mode

Unit tests without Mockito annotations
Test for calculateSum() method from service class, mocking repository. In this test, we are assuming that the retrieveAllData() mocked method from the repository returns an array with data.

@Test public void calculateSum_Should_ReturnResult_When_DataIsProvided() { //create service under test DataService ms = new DataServiceImpl(); //mock repository to test service in isolation DataRepository dataRepositoryMock = mock(DataRepository.class); when(dataRepositoryMock.retrieveAllData()).thenReturn(new int[]{1, 2, 3}); //set mock to service ms.setDataRepository(dataRepositoryMock); //call method under test int result = ms.calculateSum(); //verify if method on the mock is called by service under test //it is mostly used when a method that is called on a mock does not have a return verify(dataRepositoryMock, times(1)).retrieveAllData(); //assert result assertEquals(6, result); } 
Enter fullscreen mode Exit fullscreen mode

Test for calculateSum() method from service class, mocking repository. We are assuming that the retrieveAllData() mocked method from the repository returns an array without data.

@Test public void calculateSum_Should_ReturnZero_When_DataIsEmpty() { //create service under test DataService ms = new DataServiceImpl(); //mock repository to test service in isolation DataRepository dataRepositoryMock = mock(DataRepository.class); when(dataRepositoryMock.retrieveAllData()).thenReturn(new int[]{}); //set mock to service ms.setDataRepository(dataRepositoryMock); //call method under test int result = ms.calculateSum(); //verify if method on the mock is called by service under test verify(dataRepositoryMock, times(1)).retrieveAllData(); //assert result assertEquals(0, result); } 
Enter fullscreen mode Exit fullscreen mode

Test for calculateSum() method from service class, mocking repository. Assuming that retrieveAllData() mocked method from the repository returns null, causing the calculateSum() method from service class to throw a NullPointerException.

@Test public void calculateSum_Should_ThrowException_When_DataIsNull() { assertThrows(NullPointerException.class, () -> { //create service under test DataService ms = new DataServiceImpl(); //mock repository to test service in isolation DataRepository dataRepositoryMock = mock(DataRepository.class); when(dataRepositoryMock.retrieveAllData()).thenReturn(null); //set mock to service ms.setDataRepository(dataRepositoryMock); //call method under test ms.calculateSum(); }); } 
Enter fullscreen mode Exit fullscreen mode

Test for calculateNewSum() method from service class, mocking repository using ArgumentMatchers. In this test, we are assuming that getStoredSumById() mocked method from the repository returns 2. The new topic introduced here are ArgumentMatchers like any(), anyInt(), etc. that can be used to replace an actual argument to make tests more generic.

@Test void calculateNewSum_Should_ReturnResult_When_DataIsProvided() { //create service under test DataService ms = new DataServiceImpl(); //mock repository to test service in isolation DataRepository dataRepositoryMock = mock(DataRepository.class); //return 2 when method is called with any int value when(dataRepositoryMock.getStoredSumById(anyInt())).thenReturn(2); //set mock to service ms.setDataRepository(dataRepositoryMock); //call method under test int result = ms.calculateNewSum(1); //verify if method on the mock is called by service under test with any argument verify(dataRepositoryMock, times(1)).getStoredSumById(anyInt()); //assert result assertEquals(4, result); } 
Enter fullscreen mode Exit fullscreen mode

Test for save() method from service class, mocking repository. In this case, the save() method from the service class doesn’t return anything to be asserted. We can use an ArgumentCaptor to check if the save() method from the repository class is called with expected arguments.

@Test void save_ShouldCallRepository_With_GivenParam() { // create service under test DataService ms = new DataServiceImpl(); // mock repository to test service in isolation DataRepository dataRepositoryMock = mock(DataRepository.class); // set mock to service ms.setDataRepository(dataRepositoryMock); // call method under test Data o = new Data("MockitoObject"); ms.save(o); //create expected object Data expected = new Data("MOCKITOOBJECT"); // because the method does not return anything we can check // if mock method was called with an expected parameter ArgumentCaptor<Data> captor = ArgumentCaptor.forClass(Data.class); verify(dataRepositoryMock, times(1)).save(captor.capture()); //assert captured argument assertEquals(expected, captor.getValue()); } 
Enter fullscreen mode Exit fullscreen mode

The entire article was published at https://weinspire.tech

Top comments (0)