zoukankan      html  css  js  c++  java
  • JMockit

    简介

    JMockit是基于JavaSE5中的java.lang.instrument包开发,内部使用ASM库来动态修改java的字节码,使得java这种静态语言可以想动态脚本语言一样动态设置被Mock对象私有属性,模拟静态、私有方法行为等等website,参考这里;这里;

    JMockit有两种Mock方式:基于行为的Mock方式和基于状态的Mock方式:

    1. (基于行为的)根据输入输出,功能测试,类似黑盒测试。需要把依赖的代码mock掉,实际相当于改变了被依赖的代码的逻辑。
    2. (基于状态的)根据用例测试路径,测试代码内部逻辑,接近白盒测试。目的是测试单元测试及其依赖代码的调用过程,验证代码逻辑是否满足测试路径。
    测试解决方案
    1. Mock类的属性和行为(属性通过注入解决,行为通过对mock对象@Mocked覆盖方法)
    2. 手工注入(Deencapsulation.setField()方法)
    3. 单级注入(@Tested,@Injectable实现简单对象注入)
    4. 多级注入(需要mock对象,层层手工注入,单级注入不生效)
    5. Mock接口(覆盖率插件可能会抛错,Mock实现类,返回接口类型)
      关键字:@Tested,@Injectable,Expectations类,@Mocked{result,times,invoke()}, MokeUp<T>

    基于行为的Mock方式

    1.录制方法预期行为。
    2.真实调用。
    3.验证录制的行为被调用。

    public class GuessTest {  
      
        @Tested        // 表明被修饰实例是将会被自动构建和注入的实例,自动Mock  
        Guess guess = new Guess(3);  
        @Injectable    // 表明被修饰实例将会自动注入到@Tested修饰的实例中,并且会自动mock掉,除非在测试前被赋值  
        GuessDAO guessDAO;  
        /** 
         * 连续3次失败 
         */  
        @Test  
        public void behaviorTest_fail3time() {  
                   
            new Expectations() {        // Expectations中包含的内部类区块中,体现的是一个录制被测类的逻辑。  
                @Mocked(methods="tryIt")  // 表明被修饰的类对tryIt()方法进行mock。  
                Guess g;  
                {  
                    g.tryIt();             // 期待调用Guess.tryIt()方法  
                    result = false;        // mock掉返回值为false(表明猜不中)  
                    times = 3;             // 期待以上过程重复3次  
                    guessDAO.saveResult(false, anyInt); // 期待调用guessDAO把猜失败的结果保存  
                }  
            };  
            guess.doit();               // 录制完成后,进行实际的代码调用,也称回放(replay)  
        }  
    } 
    

    @Tested和@Injectable:
    对@Tested对象判断是否为null,是则通过合适构造器初始化,并实现依赖注入。调用构造方法时,会尝试使用@Injectable的字段进行构造器注入。普通注入时,@Injectable字段如果没有在测试方法前被赋值,其行为将会被mock成默认值(静态方法和构造函数不会被mock掉)。Injectable最大作用除了注入,还有就是mock的范围只限当前注释实例。
    总结为:@Injectable的实例会自动注入到@Tested中,如果没初始赋值,那么JMockit将会以相应规则初始化。

    @Mocked:@Mocked修饰的实例,将会把实例对应类的所有实例的所有行为都mock掉(无论构造方法,还是private,protected方法,够霸气吧)。在Expectation区块中,声明的成员变量均默认带有@Mocked,但是本例没有省略,是因为@Mocked会mock掉所有方法,而回放的代码中doit函数我们是不希望它也被mock,所以通过method="tryIt"来设置被mock的类只对tryIt方法进行mock。

    Expectations:这是录制期望发生行为的地方。result和times都是其内定成员变量。result可以重定义录制行为的返回值甚至通过Delegate来重定义行为,times是期待录制行为的发生次数。在Expectations中发生的调用,均会被mock。由于没定义result,所以guessDAO.saveResult()调用的结果返回空。

    方法二(基于行为的)

     @Test  
     public void behaviorTest_sucecess() {  
      
         new Expectations(Guess.class) {                          // 构造函数可以传入Class或Instance实例  
             {     
                 guess.tryIt();  
                 result = false;  
                 times=2;  
                 invoke(guess, "randomGuess", new Object[]{});    // invoke()能调用私有方法  
                 result = (Integer)getField(guess, "number");     // getField()能操作私有成员  
                 guessDAO.saveResult(true, (Integer)getField(guess, "number"));  
             }  
         };  
         guess.doit();  
     }  
    

    所以录制中会先调用2次tryIt并返回false,在发生第3次调用时,通过invoke调用私有方法randomGuess,并期待其返回被测实例的私有成员number,通过这种作弊的方式,自然肯定能在第三次猜中数字。最后期待guessDAO把结果保存。
    这段代码和之前的区别是,在Expectation中没定义成员变量,而把Guess.class显式地通过构造函数传入。这么做也是为了只对tryIt方法mock,因为在Expectation构造函数传入Class对象或Instance对象后,只会区块内Class或Instance对应的行为进行mock。

    方法三(基于状态的)

    使用MockUp,@Mock。通过这种方式,改变方法内部逻辑,实现类似白盒测试的功能。MockUp中的泛型类型是被重定义的类,重定义的方法需要和原类中的方法签名一致。但是,static方法可以省去static关键字。如:

    public class StateMocked {  
        public static int getDouble(int i){  
            return i*2;  
        }  
    } 
    
    @Test  
    public void testMockNormalMethodContent() throws IOException {  
        StateMocked obj = new StateMocked();  
        new MockUp<StateMocked>() {//使用MockUp修改被测试方法内部逻辑  
            @Mock  
          public int getTriple(int i) {  
                return i * 30;  
            }  
        };  
        assertEquals(30, obj.getTriple(1));  
        assertEquals(60, obj.getTriple(2));  
    }  
    


    I am a slow walker, but I never walk backwards.



  • 相关阅读:
    8.CNN应用于手写字识别
    8.优化器
    6.正则化
    5.Dropout
    4.交叉熵
    3.Minst数据集分类
    2.非线性回归
    1.线性回归
    110. Balanced Binary Tree
    106. Construct Binary Tree from Inorder and Postorder Traversal
  • 原文地址:https://www.cnblogs.com/lknny/p/5627085.html
Copyright © 2011-2022 走看看