JMockit在工作中的实战

引入JMockit

项目pom文件中添加插件配置

<plugin> 
    <groupId>com.ctrip.flight.testframework.tools</groupId>
    <artifactId>ut-maven-plugin</artifactId>
    <version>2.2.4</version>
    <executions>
        <execution>
            <phase>none</phase>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
</plugin>

引入依赖(顺序不要乱)

<dependency>
    <groupId>org.jmockit</groupId>
    <artifactId>jmockit</artifactId>
    <version>1.37</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

API

JMockit有两套API,MockUp和Expectations


new Expectations() {
	{
		instance.XXX();
		result = T;
	} 
}

MockUp

基本用法:

new MockUp<T>() {
        @Mock
        Object XXXXX() {
        	return obj
		}
} 

示例:
现有interface IDepend:

public interface IDepend {
    String getName(Object obj);

    void doSomething(Object obj1,Object obj2);
}

实现类A:

public class DependA implements IDepend {
    @Override
    public String getName(Object obj) {
        return "A";
    }

    @Override
    public void doSomething(Object obj1, Object obj2) {
        System.out.println("A Do Something");
    }
}

实现类B:

public class DependB implements  IDepend {
    @Override
    public String getName(Object obj) {
        return "B";
    }

    @Override
    public void doSomething(Object obj1, Object obj2) {
        System.out.println("B Do Something");
    }
}

待测试类:

public class Service {

    private IDepend dependA = new DependA();

    public String serviceGetName() {
        doSamething();
        return dependA.getName(new Object());
    }

    private void serviceDoSamething() {
        dependA.doSomething(new Object(), new Object());
    }
}

1.Service mock 自身serviceDoSamething

new MockUp<Service>() {
       @Mock
       void serviceDoSamething() {
   	}
} 

2.Service mock DependA的doSomething/getName

new MockUp<DependA>() {
		@Mock
		String getName(Object obj){
			// 当代码执行到dependA.getName(new Object())时,返回值为"Mock"
			return "Mock";
		}
        @Mock
        void serviceDoSamething() {
		}
} 

3.Mock继承自IDepend的所有实现类DependA,DependB

public static <T extends IDepend> void doMock() {
    new MockUp<T>() {
     	@Mock
		String getName(Object obj){
		   	// 可以根据入参obj的不同,返回不同的结果
			if (obj == null )  {
				return "Mock A";
			}
			else return "Mock B";
		}
        @Mock
        void serviceDoSamething() {
		}
    };
}

4.MockUP支持mock外部/自身的public、protected、private、static 方法,用法同上,使用方法签名+@Mock注解。
5.Mock 构造函数

class T{
	public T(){
		System.out.println("init1");
		System.out.println("init2");
		System.out.println("init3");
	}
}

执行Mock:
new MockUp<T>{
	@Mock
	 void $init(){
		// $init会对T的构造器进行拦截,原有构造器执行3次打印,拦截之后,只会执行一次"init"的打印
		System.out.println("init");
	}
}

6.模拟AOP操作

new MockUp<T>{
	@Mock
	Object $advice(Invocation invocation) {
		// $advice 会拦截所有请求
		System.out.println("执行AOP逻辑");
		// 继续调用方法
		return invocation.proceed()
	}
}

7.MockUp实现原理
在这里插入图片描述
在这里插入图片描述
基于JVM的动态加载机制(java 版本需>=1.6),通过改动原有Class对象的二进制码,重新虚拟出一个Class对象,等于在源码层面,将方法进行了替换。

Expectations

MockUP功能非常强大,支持几乎日常工作中所有可能的场景,但是当我们的代码发生变动,如新增一个参数,方法名发生变动等,原有的测试代码无法感知到,因方法签名无法匹配上最终倒是UT执行失败。

现有待mock类DependA:

class DependA{
	public String test(int index, Object obj){
		XXX;
	}
}

1.Mock 类/实例

  • mock Class(类的所有实例都会被Mock)
	@Mocked
	DependA instance ; //此处不使用@Mocked,直接new 一个实例也是可以的
	
	new Expectations(DependA.class){
            instance.test(anyint , withInstance(DependA));
        }
  • mock 实例(只mock类某一个实例,其他实例不会进入mock)
@Mocked
	DependA instance ; //此处不使用@Mocked,直接new 一个实例也是可以的
	
	new Expectations(instance){
            instance.test(anyint , withInstance(DependA));
        }

说明:上述两种情况,一种Expectations的传入参数是Class,一个是Class的具体实例。
test方法的入参,anyint, anyString, (Class)any,withInstance(Class)…均来自于Expectations的父类Invocations(抽象类),其中定义了成员变量以及方法
2.Mock 根据条件返回不同结果
关键字:Delegate
需求:需要根据入参index返回不同值,如index=0,返回null,其他返回"test"

	@Mocked
	DependA instance ;
	
	 new Expectations(VisaActionImpl.class) {
            {
                testInstance.test(anyInt, (Object) any);
                result = new Delegate() {
                    String testMock(int index, Object obj) { // 注意此处自定义的deleage方法名称,不需要与被代理方法名称一致,但是参数必须一致
                       return index == 0 ? null : "test"; //当测试用例index,传参为0时,DependA的test方法返回值即为null,其他情况则返回“test”
                    }
                };
            }
        };

3.Mock 接口
现有接口IDepend:

public interface Idepend {
    public String test();
}

现需对所有Idepend的实例的test方法进行mock:

@Capturing
Idepend testInstance;

new Expectations(){
            testInstance.test();
            result = "test";
        }

4.Returns
关键字Returns可接收一组数据,可按照条用次序依次返回结果

new Expectations(){
            testInstance.test();
            Returns("1","2","3");
        }

当test方法连续调用三次,三次mock的返回值,依次为"1",“2”,“3”

参考文档

http://jmockit.cn

发布了4 篇原创文章 · 获赞 1 · 访问量 154

猜你喜欢

转载自blog.csdn.net/weixin_36510400/article/details/104905969