首页 > 代码库 > 转jMock Cookbook 中文版三

转jMock Cookbook 中文版三

模拟泛型

Java的泛型系统不能够和它的动态反射API很好的工作.对于jMock,这意味着当你模拟泛型时编译器会警告你可能静态类型错误.警告是不正确的.避免它们最好的方法是在模拟对象声明的变量上使用一个注释抑制警告.

例如,下列泛型接口:

public interface Juicer<T extends Fruit> {    Liquid juice(T fruit);}

 

在一个测试中,你需要模拟这个接口,如下:

Juicer<Orange> orangeJuicer = context.mock(Juicer<Orange>.class, "orangeJuicer");Juicer<Coconut> coconutJuicer = context.mock(Juicer<Coconut>.class, "coconutJuicer");

 

然而,依照java语法结构这是不正确的.你实际必须写成下列内容:

Juicer<Orange> orangeJuicer = (Juicer<Orange>)context.mock(Juicer.class, "orangeJuicer");Juicer<Coconut> coconutJuicer = (Juicer<Coconut>)context.mock(Juicer.class, "coconutJuicer");

 

那些行,虽然在语句结构和语义上都是正确的,但是产生了安全警告.为了避免这些警告,你必须使用@SuppressWarnings注释变量声明:

@SuppressWarnings("unchecked")Juicer<Orange> orangeJuicer = context.mock(Juicer.class, "orangeJuicer"); @SuppressWarnings("unchecked")Juicer<Coconut> coconutJuicer = context.mock(Juicer.class, "coconutJuicer");

 

希望Java未来版本会提高泛型系统使这不是必须的.

 

使用jMock和ClassImposteriser模拟类

因为jMock使用Java的默认反射能力,所以jMock框架的默认配置仅仅可以模拟接口,不能模拟类.(事实上,我们考虑那对于我们来说是件好事,因为它鼓励设计聚焦在对象之间的通信,而不是静态分类和数据存储.)然而ClassImposteriser扩展类使用CGLIB2.1和Objenesis类库来像接口一样创建类的模拟对象.当使用遗留代码工作时对于分解紧耦合类之间的依赖关系是很有用的.

ClassImposteriser创建模拟实例不需要调用模拟类的构造函数.所以带有有参数或调用可覆盖的对象方法的构造函数的类可以被安全的模拟.然而ClassImposteriser不能创建最终类或最终方法的模拟.

如果你想模拟最终类或者最终方法,JDave类库包含了一个反最终(unfinalizer)代理设备,它在JVM加载它们前能够使类变为非最终的. 它们然后就可以通过ClassImposteriser模拟.

来使用ClassImposteriser:

1. 添加jmock-legacy-2.5.1.jar, cglib-nodep-2.1_3.jar 和 objenesis-1.0.jar到你的CLASSPATH.
2. 导入ClassImposterise到你测试类r into the Mockery of your test class:

 1 JUnit 3 2  3 import org.jmock.Expectations; 4 import org.jmock.integration.junit3.MockObjectTestCase; 5 import org.jmock.lib.legacy.ClassImposteriser; 6   7 public class ConcreteClassTest extends MockObjectTestCase { 8     { 9         setImposteriser(ClassImposteriser.INSTANCE);10     }11  12     ...13 }14 JUnit 415 16 import org.jmock.Mockery;17 import org.jmock.Expectations;18 import org.jmock.integration.junit4.JUnit4Mockery;19 import org.jmock.lib.legacy.ClassImposteriser;20  21 @RunWith(JMock.class)22 public class ConcreteClassTest {23     private Mockery context = new JUnit4Mockery() {{24         setImposteriser(ClassImposteriser.INSTANCE);25     }};26  27     ...28 }29 Other30 31 import org.jmock.Mockery;32 import org.jmock.Expectations;33 import org.jmock.lib.legacy.ClassImposteriser;34  35 public class ConcreteClassTest extends TestCase {36     private Mockery context = new Mockery() {{37         setImposteriser(ClassImposteriser.INSTANCE);38     }};39  40     ...41 }

 

3.你的测试现在可以创建抽象的或者甚至具体的类的模拟了:

Graphics g = context.mock(java.awt.Graphics.class);