Рубрики
Без рубрики

Ускоренное тестирование с помощью Mockito и JUnit 5

В этой статье мы увидим JUnit и Mockito в действии, используя 2 компонента Java, класс сервиса и… С тегами mockito, junit, java, тестирование.

В этой статье мы увидим 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”