В этой статье мы увидим JUnit и Mockito в действии, используя 2 компонента Java, класс сервиса и класс репозитория.
Мы начнем с создания классов, а затем напишем тесты различными способами, чтобы использовать такие понятия, как assert, verify, check for throwned exception, ArgumentMatcher и ArgumentCaptor. Наконец, мы создадим более чистые тесты, извлекая дублированный код и даже используя Mockitoannotations. Мы не будем фокусироваться на 100% покрытии кода.
Тестируемый код DataRepository.java
public interface DataRepository { int[] retrieveAllData(); int getStoredSumById(int id); void save(Object o); }
DataService.java
public interface DataService { int calculateSum(); void setDataRepository(DataRepository dataRepository); int calculateNewSum(int id); void save(Data o); }
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); } }
Data.java
public class Data { private String name; // constructors, getters and setters }
Модульные тесты без аннотаций Mockito Проверяют метод calculateSum() из класса service, mocking repository. В этом тесте мы предполагаем, что имитируемый метод извлечения всех данных() из репозитория возвращает массив с данными.
@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); }
Тест для метода calculateSum() из класса service, имитирующего репозиторий. Мы предполагаем, что издевательский метод извлечения всех данных() из репозитория возвращает массив без данных.
@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); }
Тест для метода calculateSum() из класса service, имитирующего репозиторий. Предполагая, что издевательский метод retrieveAllData() из репозитория возвращает значение null, в результате чего метод calculateSum() из класса service выдает исключение 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(); }); }
Тест для метода calculate New Sum() из класса service, имитирующего репозиторий с использованием ArgumentMatchers. В этом тесте мы предполагаем, что издевательский метод getStoredSumById() из репозитория возвращает 2. Новая тема, представленная здесь, – это сопоставители аргументов, такие как any(), any Int() и т.д. это может быть использовано для замены фактического аргумента, чтобы сделать тесты более универсальными.
@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); }
Тест на метод save() из класса service, имитирующий репозиторий. В этом случае метод save() из класса service не возвращает ничего, что должно быть утверждено. Мы можем использовать ArgumentCaptor, чтобы проверить, вызывается ли метод save() из класса репозитория с ожидаемыми аргументами.
@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 captor = ArgumentCaptor.forClass(Data.class); verify(dataRepositoryMock, times(1)).save(captor.capture()); //assert captured argument assertEquals(expected, captor.getValue()); }
Вся статья была опубликована по адресу https://weinspire.tech
Оригинал: “https://dev.to/gnvoicu/jumpstart-testing-with-mockito-and-junit5-13e8”