单元测试目标

维基百科对单元测试的定义:单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性测验的测试工作。程序单元是利用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是办法,包含基类(超类)、抽象类、或者派生类(子类)中的办法。单元测试的指标是隔离程序部件并证实这些单个部件是正确的。
  • 画外音:单元测试是比拟细粒度的测试,是对接口、办法、函数的测试,目标是保障代码依照正确的形式去执行,进步代码品质。

单元测试施行准则

Mock脱离数据库 + 不启动Spring + 优化测试速度 + 不引入我的项目组件

单元测试不应该依赖数据,依赖内部服务或组件等,会对其余数据产生影响的状况。启动Spring容器,个别比较慢,可能会启动音讯监听生产音讯,定时工作的执行等,对数据产生影响。

Mock测试就是在测试过程中,对那些以后测试不关怀的,不容易构建的对象,用一个虚构对象来代替测试的情景。

说白了:就是解耦(虚拟化)要测试的指标办法中调用的其它办法,例如:Service的办法调用Mapper类的办法,这时候就要把Mapper类Mock掉(产生一个虚构对象),这样咱们能够自在的管制这个Mapper类中的办法,让它们返回想要的后果、抛出指定异样、验证办法的调用次数等等。

缩小单元测试对外部的依赖和副作用,进步单元测试效率

  1. 不应用 @Autowired,@Resource, 须要启动 Spring 容器,测试速度慢,会产生副作用;
  2. 不应用 @SpringBootTest,@SpringBootTest(classes = Application.class), 这会启动整个 SpringBoot 服务
  3. 不应调用数据库,除非是做数据库操作相干的测试,尽管可配置事务回滚,但大多数状况下还是会产生脏数据等问题
  4. 应用Assert断言,用于判断某个特定条件下某个办法的行为,为了证实某段代码的执行后果和冀望的统一
  • 画外音:单元测试应小而轻,提交测试效率,较少对外部的依赖,比方数据库、Spring容器、网络服务等,而只关怀咱们本人的代码,通过Mock来解决对外部的依赖

Mockito的应用

根本应用

  1. 应用静态方法 mock()
  2. 应用注解 @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 容器治理

  1. Spy 和 Mock 生成的对象不受 Spring 治理
  2. Spy 调用实在办法时,其它 bean 是无奈注入的,要应用注入,要应用 SpyBean
  3. 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...