• 说说初用 Mock 工具测试碰到的坑


    我是一个在校实习生,作为一个程序猿,是个菜鸟中战斗机!对于测试,只写过一点点简单到不能再简单了的 Junit 单元测试的例子(因为当时这足以应付学校课程的内容与要求)。这几天在公司里要真枪实弹做测试的时候,就深深体会到了“书到用时方恨少”这句话的真谛了。没办法,谁叫我当初不多深入的学点呢。于是,在杜叔杜大神的指导下,开始了菜鸟的初用 Mock 工具,边学边用的爬坑之旅。

    为什么要用 Mock 工具?

    话不多说,我们先直接看看个最简单的例子:
    测试目标:

    public class ToBeTested {
    
        public int add(int a, int b) {
            return  a+b;
        }
        public int plus(int a, int b){
            return a*b;
        }
    }
    

    测试用例:

     public class test {
    
        @Test
        public void testEquals(){
            ToBeTested t = new ToBeTested();
            assertEquals(3,t.add(1,2));
            assertEquals(8,t.plus(2,4));
        }
    }
    

    这里我们是直接通过 new 来构建了一个 ToBeTested 的实例,因为这个类简单,而且待测试的方法里也没有依赖任何外部的对象,就一个简单的加法或乘法就完事了。但事情总是没有那么简单,在做单元测试的时候,我们要测试的方法往往都是需要依赖很多外部的对象,比如网络通讯,远程服务之类的,这些外部对象是我么没法控制的。难道这些外部依赖的对象都需要 new 一个出来吗 NO! 我们有 Mock! 我们可以用 Mock 工具来模拟这些外部对象,来完成我们的单元测试。还是先来看一个简单的 Mock 测试的例子吧:

    public class test {
    
        @Test
        public void test(){
            List<String> list = Mockito.mock(List.class);
            list.add("coding");
            verify(list).add("coding");
        }
    }
    

    坑1 : spy

    如果要用真实对象(而不是 Mock 出来的虚拟对象)中的真实的方法,则需要 spy 一下!看下面的例子:

    我在测试目标代码中加了一个 compute 函数:

    public int compute(int a){
    
            int b = add(a,a);
            int c = plus(a,a);
            return b+c;
    }
    

    随后想当然的写了个对应的测试用例:

    @Test
    
        public void testCompute(){
            ToBeTested t = new ToBeTested();
            assertEquals(8, t.compute(2));
        }
    

    但聪明的你一看就知道,这不叫单元测试。因为我只是想测试 compute 这个函数是不是正确的,但 compute 却依赖于 add 和 plus 这两个函数。如果 add 函数里有错,也会导致 compute 出错,可这根本不关 compute 的事啊。所以,测试用例代码应该是这样的:

    @Test
    
        public void testCompute(){
            ToBeTested t = spy(new ToBeTested());
            when(t.add(2,2)).thenReturn(4);
            when(t.plus(2, 2)).thenReturn(4);
            assertEquals(8, t.compute(2));
        }
    

    注意!这里 new 一个真实对象 t 的时候,需要 spy 一下!(当时年轻不懂事,被这里卡了略久。。)因为这里用到了依赖的方法 add 和 plus。现在对于这个例子,compute 的结果已经不依赖别人了,哪怕 add 方法里,不知是哪个粗心的程序猿写成了 “return a - b ",这个测试也是通过的,因为这里有 when(t.add(2,2)).thenReturn(4); 这句话,stubbing 了 add 这个方法。这也符合单元测试的概念,我们现在只负责测试 compute 这个函数,才不管 add 或 plus 正确与否呢。

    坑2:doReturn

    等等,如刚刚所说,compute 已经不依赖 add 的返回结果了,那是不是当我们测试 compute 函数的时候,add 函数是不是就可以完全无法无天的乱来了呢?我们来看看这个:

    public int add(int a, int b) {
    
            ArrayList<String> list = new ArrayList<String>();
            String s = list.get(0);
            return  a+b;
    }
    

    这时,当我们再次执行测试时,就抛异常了:java.lang.IndexOutOfBoundsException 。显然 list.get(0) 是罪魁祸首!奇怪?不是说 compute 已经不管 add 了吗? add 里面的代码有问题又怪我咯?别忘了,这还是 java 语言!所以,when(t.add(2,2)).thenReturn(4); 这语句还是会先去执行一遍 when 里面的函数, add(2,2). 至于返回结果是另外一回事。那么怎么解决这个问题呢?对!用 doReturn 语句!

     @Test
    
        public void testCompute(){
            ToBeTested t = spy(new ToBeTested());
            //when(t.add(2,2)).thenReturn(4);
            doReturn(4).when(t).add(2,2);
            when(t.plus(2, 2)).thenReturn(4);       ;
            assertEquals(8, t.compute(2));
        }
    

    现在好了, compute 已经完全不受 add 函数的影响了。add 函数爱怎么疯就怎么疯,不会影响 compute 函数的测试结果了,至此, compute 终于可以安静地完成它的单元测试了。

    坑3: PowerMock

    现如今比较流行的 Mock 工具如 jMock、EasyMock、Mockito 等都有一个共同的缺点:不能 mock 静态、final、私有方法等。而 PowerMock 能够完美的弥补以上三个 Mock 工具的不足。至于怎么做,去 Google 一下一大把的教程与实例,这里就不再多说了。。

    坑4,5,6,8,。。。。。

    慢慢踩 :)

    from: https://blog.coding.net/blog/mock-testing-tools

  • 相关阅读:
    Solr4.7+Tomcat7.0配置
    Solr suggest 搜索建议功能 配置问题
    Solr 通过经纬度指定范围搜索
    Quartz.net 实例
    log4net简单实例
    依赖注入(Autofac)
    设计模式_状态模式_C#
    C# XML操作
    策略模式_C#_设计模式
    STM32随记
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/10197965.html
Copyright © 2020-2023  润新知