我认为,能够对弹簧组件进行单元测试而无需使用临时测试配置加载完整的弹簧上下文,这是一个很大的优势,因为它干净,易于维护,编写速度更快,更改平滑。
实现此目标的一种方法是使用Mockito并告诉他用Mocks (或Spies)替换您要测试的类中的@Autowired组件。
这里举个例子。
我们有一个名为SalaryService的服务,它会根据传递的雇员ID来猜测是什么,从而计算出假设的净工资。 简单的概念。
协作者需要一项服务,第一个是EmployeeDAO,用于检索工资总额,第二个是TaxCalculator,用于根据工资总额应用一些税款。
package com.marco.springmockito;
import java.math.BigDecimal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SalaryService {private static final BigDecimal minimumSalary = new BigDecimal(20000);@Autowiredprivate EmployeeDAO employeeDAO;@Autowiredprivate 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是一项经典服务,负责从持久性存储中检索信息,并且看起来或多或少都是这样。
package com.marco.springmockito;
import java.math.BigDecimal;
import org.springframework.stereotype.Component;
@Component
public class EmployeeDAO {public BigDecimal getAnnualSalary(long employeeId) {// conncetTODB// run select for employeeId;return new BigDecimal(70000);}
}
TaxCalculator将需要TaxDao来检索税收信息,然后它将进行某种无聊且冗长的计算以退还税收。
package com.marco.springmockito;
import java.math.BigDecimal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TaxCalculator {@Autowiredprivate 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 )。
最后,我们需要在开始测试之前告诉我们的Unit框架,以操作所需的Mockito注入,然后使用
MockitoAnnotations。 initMocks(this);。
在测试中,我们需要模拟预期的操作,以便我们可以集中精力在SalaryService中要测试的实际逻辑上。
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;@InjectMocksprivate SalaryService salaryService;@Mockprivate EmployeeDAO employeeDAO;@Mockprivate TaxCalculator taxCalculator;@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Testpublic 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));}@Testpublic 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));}
}
它既简单又高效,希望对其他人有用。
翻译自: https://www.javacodegeeks.com/2014/01/testing-spring-components-with-mockito.html