关于测试工具:JavaMock简化单元测试

单元测试目标

维基百科对单元测试的定义:

单元测试(英语: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…

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理