Simulate generic
Java's generic system cannot work well with its dynamic reflection API. for jmock, this means that when you simulate generics, the compiler will warn you of possible static type errors. the warning is incorrect. the best way to avoid them is to use a comment on the variables declared by the simulated object to suppress the warning.
For example, the following generic interfaces:
public interface Juicer<T extends Fruit> { Liquid juice(T fruit);}
In a test, you need to simulate this interface as follows:
Juicer<Orange> orangeJuicer = context.mock(Juicer<Orange>.class, "orangeJuicer");Juicer<Coconut> coconutJuicer = context.mock(Juicer<Coconut>.class, "coconutJuicer");
However, this is incorrect according to the Java syntax structure. You must actually write the following content:
Juicer<Orange> orangeJuicer = (Juicer<Orange>)context.mock(Juicer.class, "orangeJuicer");Juicer<Coconut> coconutJuicer = (Juicer<Coconut>)context.mock(Juicer.class, "coconutJuicer");
Although these rows are correct in the statement structure and semantics, security warnings are generated. To avoid these warnings, you must use @ suppresswarnings to comment out the variable declaration:
@SuppressWarnings("unchecked")Juicer<Orange> orangeJuicer = context.mock(Juicer.class, "orangeJuicer"); @SuppressWarnings("unchecked")Juicer<Coconut> coconutJuicer = context.mock(Juicer.class, "coconutJuicer");
We hope that the future version of Java will improve the generic system so that this is not necessary.
Use the jmock and classimposteriser simulation classes
Because jmock uses the default reflection capability of Java, the default configuration of the jmock framework can only simulate interfaces and cannot simulate classes. (In fact, we think that is a good thing for us because it encourages design to focus on communication between objects rather than static classification and data storage .) however, the classimposteriser extension class uses the cglib2.1 and objenesis class libraries to create class simulation objects like interfaces. it is useful to break down the dependency between tightly coupled classes when using legacy code.
Classimposteriser does not need to call the constructor of the simulation class to create a simulated instance. therefore, classes with parameters or constructors that call override object methods can be safely simulated. however, classimposteriser cannot create a simulation of the final class or final method.
If you want to simulate the final class or final method, the jdave class library contains an unfinalizer proxy device, which can make the class non-final before the JVM loads them. they can then be simulated using classimposteriser.
To use classimposteriser:
1. Add jmock-legacy-2.5.1.jar, cglib-nodep-2.1_3.jar and objenesis-1.0.jar to your classpath.
2. Import classimposterise to your test class 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. You can now create abstract or even concrete class simulation for your test:
Graphics g = context.mock(java.awt.Graphics.class);