springboot 之单元测试:MockBean

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/maiyikai/article/details/78185970

代码写到一半,之前的代码只需要完成功能且对其进行优化就完事了,就在这时,突然要我加上单元测试,崩溃啊……
我也只能把它啃了。
原谅我只做过简单Java程序的单元测试,是使用Junit去Test的。
现在要使用SpringBoot和Junit去弄,好吧,我也不太懂什么是单元测试,所以就看看吧:
摘自百度百科:

单元测试(模块测试)是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。
一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。

总的来说,就是为了后期做代码优化的时候,用来判断优化后的代码是否可以得到优化前的代码执行结果。如果可以得到,那就是代码优化的很好。如果得不到,那就是优化的代码存在问题,需要进一步的深入查找问题,并且解决。这就是进行单元测试的好处。
有点归总:

进行充分的单元测试,是提高软件质量,降低开发成本的必由之路。
对于程序员来说,如果养成了对自己写的代码进行单元测试的习惯,不但可以写出高质量的代码,而且还能提高编程水平。
要进行充分的单元测试,应专门编写测试代码,并与产品代码隔离。
1、它是一种验证行为。
程序中的每一项功能都是测试来验证它的正确性。它为以后的开发提供支援。就算是开发后期,我们也可以轻松的增加功能或更改程序结构,而不用担心这个过程中会破坏重要的东西。而且它为代码的重构提供了保障。这样,我们就可以更自由的对程序进行改进。
2、它是一种设计行为。
编写单元测试将使我们从调用者观察、思考。特别是先写测试(test-first),迫使我们把程序设计成易于调用和可测试的,即迫使我们解除软件中的耦合。
3、它是一种编写文档的行为。
单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。
4、它具有回归性。
自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地的快速运行测试。
… …

使用的是spring boot + Junit;
下面我们来使用一个例子,查询用户信息:

@Service
public class Test1 {

    @Autowired
    private CheckCode checkCode;//数据校验

    @Autowired
    private Redis redis;//添加数据

    @Autowired
    private DaoService daoService;//dao层,,数据库访问层

    //查询用户信息
    public List<Object> query(String code){
        boolean flag = checkCode.isFlag(code);//数据校验

        List<Object> listData = new ArrayList<>();
        if(flag){
            listData = daoService.queryUserInfo();//访问数据库获取数据
        }else{
            //......
        }
        /**
        *重要的代码逻辑
        */
        //略

        redis.set(JSON.toJSONString(listData));//添加数据到redis,无返回值
        return listData;
    }
}

我们正常情况下:运行query(String code)这个方法,都会调用到CheckCode、DaoService 这两个类或者接口的方法,对于数据校验和数据库访问,假如我们不用考虑其对代码的影响,那么我们的单元测试可以这么写

//忘了加单元测试的注解了
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class Test2 {

    @Autowired
    private Test1 test;//这是我们一会要进行单元测试的类

    //对两个不需要验证的类进行mock
    @MockBean
    private CheckCode checkCode;//数据校验

    @MockBean
    private DaoService daoService;//dao层,,数据库访问层

    //对于不需要返回的任何值的类的所有方法,可以直接使用MockBean,直接忽略,如
    @MockBean
    private Redis redis;
    //这样写,只要是使用到redis这个对象的地方,都不会执行。直接跳过

    //第一种操作
    //为方便使用,可以使用初始化形式mock
    //公有的方法可以这样
    @Before
    public void init(){
        //这句代码的意思是:当执行到checkCode.isFlag(Mockito.anyString())方法时,返回:true
        //Mockito.anyString():任意一个String对象
        //这中方式可以将返回的值和测试代码分开,我觉得比较美观
        Mockito.when(checkCode.isFlag(Mockito.anyString())).thenReturn(true);

        //也可以使用这种
        //两种方式得到的结果是一样的
        Mockito.when(checkCode.isFlag(Mockito.anyString())).thenAnswer(new Answer<boolean>() {
            @Override
            public boolean answer(InvocationOnMock invocation) throws Throwable {
                //给出默认值
                boolean flag = true;
                //返回
                return flag;
            }});
        //两种方法都是是的isFlag(String)这个方法返回默认的值:true。


        //需要特别注意的是,不能带一个方法或者类mock两次及其以上
    }

    //单元测试的方法必须是公有的(public)、没有返回值的(void)、没有入参的()
    @Test
    public void test1(){
        Mockito.when(daoService.queryUserInfo()).thenAnswer(new Answer<List<Object>>() {
            @Override
            public List<Object> answer(InvocationOnMock invocation) throws Throwable {
                List<Object> listData = new ArrayList<>();
                //对listData赋值
                return listData;
            }});

        List<Object> data = test.query(anyString);//返回的值是上边的mock的默认值

        Assert.assertEquals(arg1,arg2);//比较是否一致,为了判断和期望值是否一致
    }
}

这样应该就可以完成一个简单的单元测试了,这些都只是伪代码,其实单元测试有很多的方法,也蛮有意思的,就是刚开始比较花时间。
其他的,后期有时间再写详细一点的。

猜你喜欢

转载自blog.csdn.net/maiyikai/article/details/78185970