乐趣区

关于测试工具: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…

退出移动版