Spring Boot中采用Mockito来mock所测试的类的依赖(避免加载spring bean,避免启动服务器)

 

最近试用了一下Mockito,感受真的挺方便的。举几个应用实例:spring

 

1,须要测试的service中注入的有一个dao,而我并不须要去测试这个dao的逻辑,只须要对service进行测试。这个时候怎么办呢,mockito就能够作到把这个dao给mock了,调用这个dao的方法会直接返回预设的值,不会去真正的执行dao里的逻辑,省时省力,专一于眼前。数据库

2,不想在单测时启动容器,加载一堆没有用的东西。这个时候你就能够把你的单元测试写成一个纯junit的test类,能够飞快的跑完测试逻辑,不用等待server加载,spring加载等乱七八糟的过程。固然这个只是一个附带的好处,主要仍是1。ide

 

下面写来一段简单的代码,稍做讲解(项目基于spring boot,其实无所谓,只要有junit,mockito,spring依赖便可,数据库配置什么的也须要本身已经配好了,这里不作说明)。函数

先来实体类:单元测试

/**
 * Created by zp on 2017/11/20.
 */
@Data
@Builder
@Entity
@Table
public class Model {
    private Long id;
    private String name;
}

Lombok注解就很少解释了。标准Bean测试

DAO:ui

/**
 * Created by zp on 2017/11/20.
 */
@Repository
public class ModelDao {
    public Model getModel(Long id){
        return Model.builder().id(id).name("model from dao ").build();
    }
}

最简单的dao,实际上应该是访问数据库,为了方便,这里构建一个对象返回出去。注意name是model from dao,由这个dao得出的对象name都会是这个,mock出来的会是另外一个。this

 

Service:spa

/**
 * Created by zp on 2017/11/20.
 */
@Service public class ModelServiceImpl implements ModelService { @Autowired ModelDao modelDao; @Override public Model getModel(Long id) { return modelDao.getModel(id); } }

接口的实现类,ModelService就一个方法,这里不写了。3d

 

好了,基础的service和dao,bean都有了。如今咱们要对ModelService作测试,按照传统的方式,Tests代码以下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    ModelService modelService;


    @Test
    public void contextLoads() {
        Model model = modelService.getModel(3L);
        System.out.println(model);
        Assert.assertEquals(3l,model.getId().longValue());
    }

}

这个会加载spring的一堆依赖,而后按照spring的注入规则,把ModelService注入进来,同时也会把ModelDao注入到ModelService中,运行一下,熟悉的画面:

 

单测会顺利经过:

 

控制台也会打印以下输出:

 

 

 可见这个是真的走的dao的代码逻辑,若是是真实业务代码,那这就去读数据库了。

这个流程虽然也能跑,可是牵扯的东西太多,还要保证ModelDao能正确注入,运行;还要加载一堆spring/server的东西,耗时耗力。

 

下面就用mockito来改写一下Tests代码,结果以下:

public class DemoApplicationTests {

    @InjectMocks
    private ModelService modelService= new ModelServiceImpl();

    @Mock
    private ModelDao modelDao;


    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        when(modelDao.getModel(any(Long.class)))
                .thenReturn(Model.builder().id(1L).name("model from mock").build());
    }

    @Test
    public void contextLoads() {
        Model model = modelService.getModel(3L);
        System.out.println(model);
        Assert.assertEquals(3l,model.getId().longValue());
    }

}

主要有如下几点变化:

1,@RunWith(SpringRunner.class),@SpringBootTest这两个注解去掉,整个Test清除了Spring Test依赖,能够避免加载额外的东西;

2,Autowire 改为以下:

    @InjectMocks                                                  
    private ModelService modelService= new ModelServiceImpl();    

再也不Autowire,而是InjetMocks,而且要本身new出Service对象;

3,添加Mock Dao的代码

@Mock                       
private ModelDao modelDao;  

表示这个对象是须要Mock的

 

4,初始化Mockito,编写Mock逻辑

@Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        when(modelDao.getModel(any(Long.class)))
                .thenReturn(Model.builder().id(1L).name("model from mock").build());
    }

重点在when()这个方法里,when函数以须要mock的方法做为参数,any表示任何输入,thenReturn设置返回的值。

这句when的意思就是当碰到modelDao的getModel函数,传入参数为任何一个Long,则直接返回一个新的,本身构建的Model对象,避免执行ModelDao的真实代码。

 

先看一下代码,mock后ModelDao不管输入任何参数,都会返回一个id为1,name为model from mock的Model对象,这个单测确定是跑不过的。让咱们来验证一下:

果真跟咱们预期的同样,而且彻底没有加载spring,直接一下就跑完了测试。

相关文章
相关标签/搜索