单元测试目标
维基百科对单元测试的定义:单元测试(英语: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...