在单元测试中,经常需要进行一些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