单元测试目标
维基百科对单元测试的定义:单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性测验的测试工作。程序单元是利用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是办法,包含基类(超类)、抽象类、或者派生类(子类)中的办法。单元测试的指标是隔离程序部件并证实这些单个部件是正确的。
- 画外音:单元测试是比拟细粒度的测试,是对接口、办法、函数的测试,目标是保障代码依照正确的形式去执行,进步代码品质。
单元测试施行准则
Mock 脱离数据库 + 不启动 Spring + 优化测试速度 + 不引入我的项目组件
单元测试不应该依赖数据,依赖内部服务或组件等,会对其余数据产生影响的状况。启动 Spring 容器,个别比较慢,可能会启动音讯监听生产音讯,定时工作的执行等,对数据产生影响。
Mock 测试就是在测试过程中,对那些以后测试不关怀的,不容易构建的对象,用一个虚构对象来代替测试的情景。
说白了:就是解耦 (虚拟化) 要测试的指标办法中调用的其它办法,例如:Service 的办法调用 Mapper 类的办法,这时候就要把 Mapper 类 Mock 掉(产生一个虚构对象),这样咱们能够自在的管制这个 Mapper 类中的办法,让它们返回想要的后果、抛出指定异样、验证办法的调用次数等等。
缩小单元测试对外部的依赖和副作用,进步单元测试效率
- 不应用 @Autowired,@Resource, 须要启动 Spring 容器,测试速度慢,会产生副作用;
- 不应用 @SpringBootTest,@SpringBootTest(classes = Application.class), 这会启动整个 SpringBoot 服务
- 不应调用数据库,除非是做数据库操作相干的测试,尽管可配置事务回滚,但大多数状况下还是会产生脏数据等问题
- 应用 Assert 断言,用于判断某个特定条件下某个办法的行为,为了证实某段代码的执行后果和冀望的统一
- 画外音:单元测试应小而轻,提交测试效率,较少对外部的依赖,比方数据库、Spring 容器、网络服务等,而只关怀咱们本人的代码,通过 Mock 来解决对外部的依赖
Mockito 的应用
根本应用
- 应用静态方法 mock()
- 应用注解 @Mock 标注
如果应用 @Mock 注解, 必须去触发所标注对象的创立. 能够应用 MockitoRule 来实现. 它调用了静态方法 MockitoAnnotations.initMocks(this) 去初始化这个被注解标注的字段. 或者也能够应用 @RunWith(MockitoJUnitRunner.class).
“when thenReturn”和”when thenThrow”
模仿对象能够依据传入办法中的参数来返回不同的值, when(….).thenReturn(….)办法是用来依据特定的参数来返回特定的值.
咱们也能够应用像 anyString 或者 anyInt anyLong any 这样的办法来定义某个依赖数据类型的办法返回特定的值.
“doReturn when”和“doThrow when”
doReturn(…).when(…)的办法调用和 when(….).thenReturn(….)相似. 对于调用过程中抛出的异样十分有用. 而 doThrow 则也是它的一个变体.
罕用注解
@Mock:对函数的调用均执行 mock(即虚伪函数),不执行真正局部。
@Spy:对函数的调用均执行真正局部。
@InjectMocks:创立一个实例,简略的说是这个 Mock 能够调用实在代码的办法,应用 @Mock(或 @Spy)注解创立的 mock 将被注入到用该实例中。
Mockito 中的 Mock 和 Spy 都可用于拦挡那些尚未实现或不冀望被实在调用的对象和办法,并为其设置自定义行为。二者的区别在于 Mock 不实在调用,Spy 会实在调用。
@MockBean: 性能同 @Mock, 只是会将实例放入 Spring 容器治理
@SpyBean: 性能同 @Spy, 只是会将实例放入 Spring 容器治理
- Spy 和 Mock 生成的对象不受 Spring 治理
- Spy 调用实在办法时,其它 bean 是无奈注入的,要应用注入,要应用 SpyBean
- SpyBean 和 MockBean 生成的对象受 Spring 治理,相当于主动替换对应类型 bean 的注入,比方 @Autowired、@Resource 等注入
最佳实际
// 不应用 @SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class ExamAnswerComponentTest {
// 创立一个实例,会注入 Mock 变量
@InjectMocks
private ExamAnswerComponent examAnswerComponent = new ExamAnswerComponentImpl();
// 相干操作会被 Mock 掉
@Mock
private ExamAnswerCacheObjectiveDAO examAnswerCacheObjectiveDAO;
@Before
public void setUp() {
// 初始化 Mock
MockitoAnnotations.initMocks(this);
// given...willReturn 指定办法参数,模仿返回值
given(examAnswerCacheObjectiveDAO.selectByBizIdAndPaperAndQuestion(any(), any(), any()))
.willReturn(new ExamAnswerCacheObjectivePO());
given(examAnswerCacheObjectiveDAO.insert(any())).willReturn(1);
given(examAnswerCacheObjectiveDAO.updateUserAnswerById(any(), any())).willReturn(1);
}
@Test
public void saveOrUpdateAnswerCacheObjective() {ExamAnswerCacheObjectivePO po = new ExamAnswerCacheObjectivePO();
po.setBizId(100000015L);
po.setBizType(9);
po.setUserAnswer("A");
po.setGroupPaperId(1000320L);
po.setQuestionId(1000042L);
po.setQuestionType(1);
int affect = examAnswerComponent.saveOrUpdateAnswerCacheObjective(po);
System.out.println("affect =" + affect);
Assert.assertTrue(affect > 0);
}
}
参考
https://www.codenong.com/cs10…