mockito使用

为什么使用mockito

设想一个刚开始学习编程的学生如何处理测试?

public static void main(String[] args) {
    List<String> strings = Lists.newArrayList("string1", "string2");
    
    if(!"STRING1".equals(strings)) {
        throw new SomeException();
    }
}

一般情况下需要这三步走:

  1. 新建一个执行入口main
  2. 编写一些测试数据
  3. 执行逻辑,然后看一下逻辑是否与自己设想的一致

这个流程正确吗?没问题的,这个流程是完整的,且可行的; 但是,比较麻烦,麻烦的地方在于总是需要新建一个主类入口,总是需要肉眼看下是否符合逻辑;(好像总是需要编写测试数据不好避过?)

那么,如何优雅的处理这个问题呢?

  • junit: 控制测试流程,处理测试事务
  • mockito: 管理方法行为,控制方法输入输出,测试最小粒度的逻辑正确
  • Assertion, Verify: 如何自动的测试一个逻辑过程的正确性 所以,测试框架主要解决的是这三个问题,下面的三个主题,主要是为了解释这三个问题。

什么是Junit,如何使用Junit

简单理解,Junit是一个能够框架性的解决单元测试的框架。意味着,你可以使用Junit来无牵连的解决单独一个子模块,一个方法的正确性。 Junit集成了很多的流程控制,数据、结论的验证方面的处理;另外,Junit更像是一个框架,可以通过Junit来赋予三方开发者对你的框架的测试能力。例如,Spring通过适配Junit,允许Spring的开发者进行Spring的测试

由于对Junit的讲解文章非常多,本文不多做Junit的使用讲解。

实例代码:

public class TestSomething {

    // 添加Test表名一个最小的测试单元
    @Test
    public void test() {
        // 调用一个服务获取到结果
        int returnCode = someService.getReturnCode();
        // 判断是否符合预期
        assertEqual(returnCode, 0);
    }
}

什么是Mockito,如何使用Mockito

理解一个问题:如果我的测试是为了测试一个最小的逻辑单元,但是因为我的逻辑单元需要用到其他的逻辑提供方(比如说一个service),那么如何能够做到不连带测试这个逻辑提供方呢?

Mockito能够解决这个问题。Mockito通过反射的机制,约束测试对象的内部行为,最小化的实现一个类的方法的逻辑。在此基础上,测试一个方法的行为;这种说法比较抽象,我们看下面的代码:

我们需要实现这样一个逻辑/方法: 这个方法被调用的时候,会从一个天气的接口中获取当天的气温,获取到气温后进行判断给出当天的警报状态

  1. 假设我们要测试的service如下:
public class WeatherWarningServiceImpl implements WeatherWarningService {
    private static final String NORMAL = "NORMAL";
    private static final String COLD = "COLD";
    private static final String HOT = "HOT";

    private static final int HOT_LIMIT  = 30;
    private static final int COLD_LIMIT = 0;
    
    private TemperaturService tempService;

    public String getWarningMsg() {
        int temperature = tempService.getTemp();
        if(temperature > HOT_LIMIT) {
            return HOT;
        }
        if(temperatur < COLD_LIMIT) {
            return COLD;
        }
        return NORMAL;
    }

}

我们分析下上面这个方法: 这个方法已经是一个最小的逻辑体,但是实现的过程中使用到了一个 tempService, 传统的测试办法中,需要使这个服务在测试中可用,这样会有很多的问题

  1. 大部分时候无法是这个服务可用
  2. 如果非得是这个服务可用的话,破坏了最小原则,单一职能原则
  3. 使用Spring的测试框架话,测试耗时会非常的长

如果我们只是为了测试 getWarningMsg的逻辑是否正确,那么只要能够约束、控制tempServvice#getTemp的行为就非常的nice:Mockito就能够起到这样的作用。继续写


@Runwith(MockitoRunner.class)
public class TestWithMockito {

    /**
    * 被测试的服务的对象
    */
    @InjectMock
    private WeatherWarningServiceImpl weatherWarningService;

    // 测试对象需要的property,需要时可以实例化的类,不可以使用interface,和abstract类
    @Mock
    private TemperatureServiceImpl tempService;

    @Test
    public void test() {

        // 约束 tempService的行为, 使该方法始终返回35
        when(tempService.getTemp()).thenReturn(35);

        String warningMsg = weatherWarningService.getWarningMsg();
        assertEqual(HOT, warningMsg);
    }

}

Written on July 4, 2020 Author: CINQS