Возможность модульного тестирования компонентов пружины без необходимости загрузки полного контекста пружины с его специальными конфигурациями тестирования, на мой взгляд, является большим преимуществом, поскольку она чиста, проста в обслуживании, быстрее пишется, плавно изменяется ,
Чтобы достичь этой цели, используйте Mockito и попросите его заменить компоненты @Autowired в классе, который вы хотите протестировать, на Mocks (или Spies).
Вот пример.
У нас есть сервис под названием SalaryService, который угадает что, вычисляет гипотетическую чистую зарплату на основе переданного идентификатора сотрудника. Простая концепция.
Служба требовала, чтобы сотрудники, один из которых, EmployeeDAO, получал брутто-зарплату, а второй, TaxCalculator, применял некоторые налоги на основе брутто-зарплаты.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package com.marco.springmockito;import java.math.BigDecimal;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Componentpublic class SalaryService { private static final BigDecimal minimumSalary = new BigDecimal(20000); @Autowired private EmployeeDAO employeeDAO; @Autowired private TaxCalculator taxCalculator; public BigDecimal getNetSalary(long employeeId) { BigDecimal netSalary = null; BigDecimal grossSalary = employeeDAO.getAnnualSalary(employeeId); BigDecimal taxes = taxCalculator.calculateTaxes(grossSalary); if (taxedSalaryIsGreaterThanMinimumSalary(grossSalary)) { netSalary = grossSalary.subtract(taxes); } else { netSalary = grossSalary; } return netSalary; } private boolean taxedSalaryIsGreaterThanMinimumSalary(BigDecimal taxedSalary) { return taxedSalary.compareTo(minimumSalary) == 1; }} |
EmployeeDAO — это классическая служба, которая отвечает за извлечение информации из постоянного хранилища, и будет выглядеть примерно так.
|
01
02
03
04
05
06
07
08
09
10
11
12
|
package com.marco.springmockito;import java.math.BigDecimal;import org.springframework.stereotype.Component;@Componentpublic class EmployeeDAO { public BigDecimal getAnnualSalary(long employeeId) { // conncetTODB // run select for employeeId; return new BigDecimal(70000); }} |
TaxCalculator понадобится TaxDao для получения информации о налогах, а затем он будет выполнять какие-то скучные и долгие вычисления для возврата налогов.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
package com.marco.springmockito;import java.math.BigDecimal;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Componentpublic class TaxCalculator { @Autowired private TaxDao taxDao; public BigDecimal calculateTaxes(BigDecimal salary) { BigDecimal result = salary.multiply(taxDao.getTaxPercentageForYear(2014)); // some other weird calculation .... return result; }} |
Теперь мы хотим провести модульное тестирование класса SalaryService. Нас не должны беспокоить какие-либо настройки DAO и баз данных. В этом тесте UNIT нам все равно, что делает TaxCalculator.
Мы хотим проверить, работает ли наш SalaryService так, как ожидается, и способен ли он правильно использовать работу своих сотрудников.
Вот как мы это делаем с Mockito. Мы помечаем класс, который мы хотим протестировать, с помощью @InjectMocks и помечаем @Mock всех его соавторов (или @Spy, если вам нужна реальная реализация).
Наконец, мы должны сообщить нашей структуре блока, чтобы выполнить необходимые инъекции Mockito перед началом теста, и мы делаем это с
MockitoAnnotations. initMocks (это) ;.
В тесте нам нужно смоделировать ожидаемые операции, чтобы мы могли сосредоточиться на реальной логике, которую мы хотим проверить внутри SalaryService.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package com.marco.springmockito;import static org.hamcrest.core.Is.is;import static org.junit.Assert.assertThat;import static org.mockito.Mockito.when;import java.math.BigDecimal;import org.junit.Before;import org.junit.Test;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.MockitoAnnotations;public class SalaryServiceTest { private static final long UserId = 123l; @InjectMocks private SalaryService salaryService; @Mock private EmployeeDAO employeeDAO; @Mock private TaxCalculator taxCalculator; @Before public void init() { MockitoAnnotations.initMocks(this); } @Test public void testMinimumSalary() { BigDecimal annualSalary = new BigDecimal(10000); when(employeeDAO.getAnnualSalary(UserId)).thenReturn(annualSalary); when(taxCalculator.calculateTaxes(annualSalary)).thenReturn(new BigDecimal(1000)); BigDecimal actual = salaryService.getNetSalary(UserId); assertThat(actual.compareTo(new BigDecimal(10000)), is(0)); } @Test public void testMaximumSalary() { BigDecimal annualSalary = new BigDecimal(80000); when(employeeDAO.getAnnualSalary(UserId)).thenReturn(annualSalary); when(taxCalculator.calculateTaxes(annualSalary)).thenReturn(new BigDecimal(8000)); BigDecimal actual = salaryService.getNetSalary(UserId); assertThat(actual.compareTo(new BigDecimal(72000)), is(0)); }} |
Это просто и эффективно, и, надеюсь, это будет полезно для кого-то еще там.