`

Jmockit 入门

阅读更多

在单元测试中,经常需要进行一些mock操作。现在已经有了一些比较不错的框架在做这些事情,比如:EasyMck,他在大多数情况下运行良好,但是对于某些结构的设计却显得无能为力。

EasyMock等众多的mock框架仅能mock一些public,non static or final的方法,在大多数情况下这并没有什么问题,他可以处理大多数的问题,但是当测试的代码包含了一些静态方法,可能就让问题变得难以解决,有一种选 择即是重构他(过多的静态方法可能预示着这并不是一个很好的设计),但是当你使用外部引用库所提供的方法,问题又该如何解决呢?

JMockit是一个能帮我们解决以上问题的轻量级框架,他允许你动态的改变已有的方法,这主要基于java 1.5的Instrumentation框架,这样便可以使得JMockit能够适应几乎所有的设计。他允许你重定义private,static and final方法,甚至是no-arg constructors都能够并轻易的重定义。

在实际的项目中有些方法可以重定义而有些不行,为了更好的说明如何对方法进行重定义,下面有一个简单的类和对应测试代码的demo,他尽可能考虑到了几乎所有的情况,供大家方便的学习。(理解不透的地方,希望大家指正)

package jmockit;

public class ClassToMock {
	private String memberToSet = "";
    private static String staticMember;
    
    static {
        staticMember = "Static initialized";
    }
    
    public ClassToMock() {
        this.memberToSet = "Member set by original constructor";
    }
    public ClassToMock(String value){
    	this.memberToSet = value;
    }
    public String publicMethod() {
            return "Original public method";
    }
    protected String protectedMethod() {
            return "Original protected method";
    }
    String defaultMethod() {
            return "Original default method";
    }
    public String methodThatUsesPrivateMethod() {
            return privateMethod();
    }
    private String privateMethod() {
            return "Original private method";
    }
    public String getMemberToSet() {
            return memberToSet;
    }
    public String getStaticMember() {
            return staticMember;
    }
}

 
package jmockit;

import static org.junit.Assert.assertEquals;
import mockit.Mockit;

import org.junit.Before;
import org.junit.Test;

public class ClassToMockTest {

private ClassToMock mockedClass;

public static class Replacement {

static {
}

public Replacement() {
}

public Replacement(String test) {
}

public String publicMethod() {
return "Replaced public method";
}

public String protectedMethod() {
return "Replaced protected method";
}

public String defaultMethod() {
return "Replaced default method";
}

public String privateMethod() {
return "Replaced private method";
}
}

@Before
public void setUp() throws Exception {
Mockit.redefineMethods(ClassToMock.class, Replacement.class);
mockedClass = new ClassToMock("test");
}

protected void tearDown() throws Exception {
Mockit.restoreAllOriginalDefinitions();
}

/**
* Public methods can be replaced
*/
@Test
public void testReplacePublic() {
assertEquals("Replaced public method", mockedClass.publicMethod());
}

/**
* Protected methods can be replaced.
* The replacement method should be declared public however
*/
@Test
public void testReplaceProtected() {
assertEquals("Replaced protected method", mockedClass.protectedMethod());
}

/**
* Package accessable methods can be replaced
* The replacement method should be declared public however
*/
@Test
public void testReplaceDefault() {
assertEquals("Replaced default method", mockedClass.defaultMethod());
}

/**
* Private methods can be replaced
* The replacement method should be declared public however
*/
@Test
public void testReplacePrivate() {
assertEquals("Replaced private method", mockedClass
.methodThatUsesPrivateMethod());
}

/**
* Non-default constructors can be replaced
* Your mock definition must have a default constructor however
*/
@Test
public void testReplaceConstructor() {
assertEquals(null, mockedClass.getMemberToSet());
}

/**
* Default constructors <b>can't</b> be replaced
*/
@Test
public void testReplaceDefaultConstructor() {
mockedClass = new ClassToMock();
assertEquals("Member set by original constructor", mockedClass
.getMemberToSet());
}
/**
* Static initializers <b>can't</b> be replaced
*/
@Test
public void testReplaceStaticBlock() {
assertEquals("Static initialized", mockedClass.getStaticMember());
}
}
 注意要导包。
 官方文档:https://jmockit.dev.java.net/tutorial.html
分享到:
评论
7 楼 solviv 2010-08-24  
疯狂的草儿 写道
solviv 写道
大哥,使用你的方式进行了测试,可能使用的版本不正确,总是提示确认JVM是否已经启动:
Caused by: java.lang.IllegalStateException: JMockit has not been initialized. Check that your Java 5 VM has been started with the -javaagent:D:\jmockit\lib\jmockit.jar command line option.

jmockit的jar包路径是没有问题的,通过命令行执行的时候总是提示类未定义:
Caused by: java.lang.ClassNotFoundException: junit.framework.TestSuite
这几个类都是可以找到的,我使用的junit-4.8.2.jar.

在IDE中配置了jvm参数后执行提示:
java.lang.VerifyError: (class: org/junit/runner/notification/RunNotifier, method: addFirstListener signature: (Lorg/junit/runner/notification/RunListener;)V) Illegal constant pool index
这个错误google了好久没找到解决办法.

而且jmockit更新为最新版本的jar包以后,示例中提到的方法已经没有了,学习了下,还没头绪,不知道你使用过程中是否有遇到类似问题,还请指教下,谢谢.



我这边有jmockit的jar包,你下载一下。
我的MyEclipse7.0 我的junit版本是4.4.5的
这个例子已经是好久的了 我刚开始用的时候就是采用这个列子的
现在也几乎不这样用了
直接用 @Mocked 去注解你要mock的对象,然后再在 new Expectations中去 指定mock的方法和返回值 等等


OK,搞定.环境更新后(jdk1.6,junit4.7,jmockit-0.999.1),按你的方式处理,可以正常对静态方法进行替换了.
之前不太确定是否jdk版本的问题,有空再研究下,多谢了!
6 楼 疯狂的草儿 2010-08-24  
solviv 写道
大哥,使用你的方式进行了测试,可能使用的版本不正确,总是提示确认JVM是否已经启动:
Caused by: java.lang.IllegalStateException: JMockit has not been initialized. Check that your Java 5 VM has been started with the -javaagent:D:\jmockit\lib\jmockit.jar command line option.

jmockit的jar包路径是没有问题的,通过命令行执行的时候总是提示类未定义:
Caused by: java.lang.ClassNotFoundException: junit.framework.TestSuite
这几个类都是可以找到的,我使用的junit-4.8.2.jar.

在IDE中配置了jvm参数后执行提示:
java.lang.VerifyError: (class: org/junit/runner/notification/RunNotifier, method: addFirstListener signature: (Lorg/junit/runner/notification/RunListener;)V) Illegal constant pool index
这个错误google了好久没找到解决办法.

而且jmockit更新为最新版本的jar包以后,示例中提到的方法已经没有了,学习了下,还没头绪,不知道你使用过程中是否有遇到类似问题,还请指教下,谢谢.



我这边有jmockit的jar包,你下载一下。
我的MyEclipse7.0 我的junit版本是4.4.5的
这个例子已经是好久的了 我刚开始用的时候就是采用这个列子的
现在也几乎不这样用了
直接用 @Mocked 去注解你要mock的对象,然后再在 new Expectations中去 指定mock的方法和返回值 等等
5 楼 solviv 2010-08-23  
大哥,使用你的方式进行了测试,可能使用的版本不正确,总是提示确认JVM是否已经启动:
Caused by: java.lang.IllegalStateException: JMockit has not been initialized. Check that your Java 5 VM has been started with the -javaagent:D:\jmockit\lib\jmockit.jar command line option.

jmockit的jar包路径是没有问题的,通过命令行执行的时候总是提示类未定义:
Caused by: java.lang.ClassNotFoundException: junit.framework.TestSuite
这几个类都是可以找到的,我使用的junit-4.8.2.jar.

在IDE中配置了jvm参数后执行提示:
java.lang.VerifyError: (class: org/junit/runner/notification/RunNotifier, method: addFirstListener signature: (Lorg/junit/runner/notification/RunListener;)V) Illegal constant pool index
这个错误google了好久没找到解决办法.

而且jmockit更新为最新版本的jar包以后,示例中提到的方法已经没有了,学习了下,还没头绪,不知道你使用过程中是否有遇到类似问题,还请指教下,谢谢.


4 楼 疯狂的草儿 2010-08-13  
rocket 写道
不错,其实jmockit最强的是对静态方法和构造函数的模拟,直接改jvm启动时候的classloader。楼主有没有时间把jmockit的所有用法出个手册出来,我一直想做,没有时间搞啊,或者我们两个一起做一个manual来方便大家

Good idear.My qq is 55652199.
但是jmockit的官方资料实在不全,并且上面的例子 也十分复杂。
我做单元测试用的最多的也就是
new NonExpectations(){{}};.....
希望可以合作。
3 楼 rocket 2010-08-12  
不错,其实jmockit最强的是对静态方法和构造函数的模拟,直接改jvm启动时候的classloader。楼主有没有时间把jmockit的所有用法出个手册出来,我一直想做,没有时间搞啊,或者我们两个一起做一个manual来方便大家
2 楼 疯狂的草儿 2010-06-07  
不会的啊 报的什么错

是不是环境没有搭建好
导包的时候 先导junit 再导 jmockit
1 楼 airpeng 2010-06-02  
怎么跑不起来啊??

相关推荐

Global site tag (gtag.js) - Google Analytics