Jmockit入门操作(一)

了解Mock

单测是软件开发中比不可少的工序,高效的测试方法,良好的测试习惯,全面的测试范围保证了代码的质量。

在测试方法中mock测试是Java程序员常用的一种测试方法。mock本意是对于一些不容易构造/获取的对象,创建一个mock对象来模拟对象的行为。mock对象就是真实对象在调试期间的代替品。

什么场景使用moke测试?

  • 1、当另一方接口或服务还未完成,阻碍项目进度时,可以通过mock的方式,实现并行开发。
  • 2、另一方接口不稳定,而这边需要一个稳定的结果才能继续往下走流程时,也可以使用mock。有时候自动化测试需要一个持续稳定的环境,也可以对不是很重要的服务进行mock处理。
  • 3、需要模拟异常情况,但是这种异常不容易触发时,可以使用mock实现。

Jmock入门

JMockit是一款Java类/接口/对象的Mock工具,目前广泛应用于Java应用程序的单元测试中。主要特点是Api操作简单,容易上手。

环境依赖:pom.xml文件配置

<!-- 先声明jmockit的依赖 -->
   <dependency>
    <groupId>org.jmockit</groupId>
    <artifactId>jmockit</artifactId>
    <version>1.36</version>
    <scope>test</scope>
  </dependency>
<!-- 再声明junit的依赖 -->
   <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.9</version>
    <scope>test</scope>
  </dependency>

mock对象可以包括:类,实例对象,接口以及开源框架中的场景SpringBean、Dubbo中的bean、MQ中的消费者等等

下面以常用的类,实例对象,接口为演示示例:

mock类使用Expectations简单示例:

/**
 * 普通类包含static方法,普通方法,final方法,private方法,调用private方法
 */
public class AnOrdinary {
    // 静态方法
    public static int staticMethod() {
        return 1;
    }
    // 普通方法
    public int ordinaryMethod() {
        return 2;
    }

    // final方法
    public final int finalMethod() {
        return 3;
    }
    // private方法
    private int privateMethod() {
        return 5;
    }

    // 调用private方法
    public int callPrivateMethod() {
        return privateMethod();
    }
}

/**
 * 测试类
 */

@RunWith(JMockit.class)
public class ClassMockingByExpectationsTest {
    private static ClassMockingByExpectationsTest JNITools;

    @Test
    public void testClassMockingByExpectation() {
        final AnOrdinary instanceToRecord = new AnOrdinary();
        new Expectations(AnOrdinary.class) {
            {
                // mock静态方法
                AnOrdinary.staticMethod();
                result = 10;
                // mock普通方法
                instanceToRecord.ordinaryMethod();
                result = 20;
                // mock final方法
                instanceToRecord.finalMethod();
                result = 30;
            }
        };
        AnOrdinary instance = new AnOrdinary();
        Assert.assertTrue(AnOrdinary.staticMethod() == 10);
        System.out.println(AnOrdinary.staticMethod());
        Assert.assertTrue(instance.ordinaryMethod() == 20);
        System.out.println(instance.ordinaryMethod());
        Assert.assertTrue(instance.finalMethod() == 30);
        System.out.println(instance.finalMethod());
        Assert.assertTrue(instance.callPrivateMethod() == 5);
        System.out.println(instance.callPrivateMethod());
    }
}

在上述代码中,Expectations构造了AnOrdinary类的测试返回值。其中callPrivateMethod方法并没有执行mock测试中的返回值,仍然返回代码中的初始值。

mock类mockup示例:

/**
 * mockup测试类
 */
@RunWith(JMockit.class)
public class ClassMockingByMockupTest {
    // AnOrdinary的MockUp类,继承MockUp即可
    public static class AnOrdinaryMockUp extends MockUp<AnOrdinary> {
        // Mock静态方法
        @Mock
        public static int staticMethod() {
            return 10;
        }
        // Mock普通方法
        @Mock
        public int ordinaryMethod() {
            return 20;
        }
        @Mock
        // Mock final方法
        public final int finalMethod() {
            return 30;
        }
        // Mock private方法
        @Mock
        private int privateMethod() {
            return 50;
        }
    }

    @Test
    public void testClassMockingByMockupT() {

        new AnOrdinaryMockUp();
        AnOrdinary instance = new AnOrdinary();
        // 静态方法被mock了
        Assert.assertTrue(AnOrdinary.staticMethod() == 10);
        System.out.println(AnOrdinary.staticMethod());
        // 普通方法被mock了
        Assert.assertTrue(instance.ordinaryMethod() == 20);
        System.out.println(instance.ordinaryMethod());
        // final方法被mock了
        Assert.assertTrue(instance.finalMethod() == 30);
        System.out.println(instance.finalMethod());
        // private方法被mock了
        Assert.assertTrue(instance.callPrivateMethod() == 50);
        System.out.println(instance.callPrivateMethod());
    }
}


//mockup还可以以内部类的形式表示

基础mockup类 ,实现mock返回数据

mock实例和mock类方式相似,只不顾类名变成实例引用:

//mock实例
public class InstanceMockingByExpectationsTest {
    @Test
    public void testInstanceMockingByExpectation() {
        AnOrdinaryClass instance = new AnOrdinaryClass();
        // 直接把实例传给Expectations的构造函数即可Mock这个实例
        new Expectations(instance) {
            {
                // 尽管这里也可以Mock静态方法,但不推荐在这里写。静态方法的Mock应该是针对类的
                // mock普通方法
                instance.ordinaryMethod();
                result = 20;
                // mock final方法
                instance.finalMethod();
                result = 30;
                // native, private方法无法用Expectations来Mock
            }
        };
    
    }

mock接口:

//一个普通的接口
public interface AnOrdinaryInterface {
    // 方法1
    public int method1();
 
    // 方法2
    public int method2();
}

//用Expectations来mock接口
public class InterfaceMockingByExpectationsTest {
 
    // 通过@Injectable,让JMockit帮我们生成这个接口的实例,
    // 一般来说,接口是给类来依赖的,我们给待测试的类加上@Tested,就可以让JMockit做依赖注入。详细见JMockit基础的章节
    @Injectable
    AnOrdinaryInterface anOrdinaryInterface;
 
    @Test
    public void testInterfaceMockingByExpectation() {
        // 录制
        new Expectations() {
            {
                anOrdinaryInterface.method1();
                result = 10;
                anOrdinaryInterface.method2();
                result = 20;
            }
        };
        Assert.assertTrue(anOrdinaryInterface.method1() == 10);
        Assert.assertTrue(anOrdinaryInterface.method2() == 20);
    }
}

//用MockUp来mock接口
public class InterfaceMockingByMockUpTest {
 
    @Test
    public void testInterfaceMockingByMockUp() {
        // 手工通过MockUp创建这个接口的实例
        AnOrdinaryInterface anOrdinaryInterface = new MockUp<AnOrdinaryInterface>(AnOrdinaryInterface.class) {
            // 对方法Mock
            @Mock
            public int method1() {
                return 10;
            }
 
            @Mock
            public int method2() {
                return 20;
            }
        }.getMockInstance();
 
        Assert.assertTrue(anOrdinaryInterface.method1() == 10);
        Assert.assertTrue(anOrdinaryInterface.method2() == 20);
    }
}

原理分析: 

      熟悉Jmock的使用方法,在回过头来看看具体的实现逻辑, 录制(ExpectationsTransformer)和伪类(ClassLoadingBridgeFields)是Jmockit两种类型的测试方法

    基于行为的Mock方式:用于对new Expectations(){{}},new Verifications(){{}},匿名类进行重定义。用于支持测试程序中的录制,重放,校验。基本步骤为:.录制方法预期行为;真实调用;验证录制的行为被调用。
    基于状态的Mock方式:   即new MockUp<T> {}的匿名类或 extends MockUp<T>的子类。用于伪类的@Mock方法提供支持。 通过识别伪类@Mock方法,在对应的方法体中织入一段分支,用于走伪类的@Mock方法逻辑。

参考博客:https://www.jianshu.com/p/de8a3dc04f82

                  https://blog.csdn.net/chjttony/article/details/17838693

Jmcok中文网:http://jmockit.cn/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值