Because jmock uses Java's standard reflection mechanism, the jmock framework can only be configured with mock interface objects by default, rather than mock class objects. However, using cglib 2.1 and the objenesis library and classimposteriser extension can not only mock interface objects, but also mock class objects.
Classimposteriser extended usage and instance description
When the classimposteriser mock instance object is used, the class constructor of the mock class will not be called. Therefore, classes with multiple parameters or constructors that need to call the overload method can be safely mock, however, it cannot be mockfinal class or a class with a final method. To use mock final class, you must first use the jdave library to remove the final feature of class before the class is loaded into JVM.
Next let's take a look at how to use classimposteriser to mock class.
- Add the following three jar packages to the class path
- In the Code, set classimposteriser when creating the mock context.
import org.jmock.Mockery;import org.jmock.Expectations;import org.jmock.integration.junit4.JUnit4Mockery;import org.jmock.lib.legacy.ClassImposteriser; @RunWith(JMock.class)public class ConcreteClassTest { private Mockery context = new JUnit4Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; ...}
- Then the mock class object can be implemented according to the common method.
private ExterfaceImpl target; private final static Mockery mockContext = new JUnit4Mockery() { { setImposteriser(ClassImposteriser.INSTANCE); } }; private Helper helper = null; // static { // mockery.setImposteriser(ClassImposteriser.INSTANCE); // } @Before public void setUp() throwsException { target = new ExterfaceImpl(); helper =mockContext.mock(Helper.class); target.setHelper(helper); }
Related Issues
However, when classimposteriser is used for mock class, it is found that a new problem is different from that of mock interface. That is, when multiple unit test cases (functions annotated with @ test) are written in a Java file, an error is reported, and the first test case can pass, none of them can pass.
@Test public voidtestGetExterfaceInvokeByPartnerId() { return; Object result =target.getById(null, null, null); Assert.assertNull(result); } @Test public void testGetExterfaceInvokeByPartnerId1() { return; Object result =target.getById(null, null, null); Assert.assertNull(result); }
The error message is as follows:
Java. Lang. illegalargumentexception: a mock with name exthelper already exists
Atorg. jmock. mockery. Mock (mockery. Java: 128)
Atcom. Alipay. mapitool. facade. exterface. impl. exterfaceinvokefacadeimplunittest. Setup (exterfaceinvokefacadeimplunittest. Java: 54)
Atsun. Reflect. nativemethodaccessorimpl. invoke0 (native method)
Atsun. Reflect. nativemethodaccessorimpl. Invoke (nativemethodaccessorimpl. Java: 39)
Atsun. Reflect. delegatingmethodaccessorimpl. Invoke (delegatingmethodaccessorimpl. Java: 25)
Atjava. Lang. Reflect. method. Invoke (method. Java: 597)
Atorg. JUnit. Internal. Runners. methodroadie. runbefores (methodroadie. Java: 122)
Atorg. JUnit. Internal. Runners. methodroadie. runbeforesthentestthenafters (methodroadie. Java: 86)
Atorg. JUnit. Internal. Runners. methodroadie. runtest (methodroadie. Java: 77)
Atorg. JUnit. Internal. Runners. methodroadie. Run (methodroadie. Java: 42)
Atorg. JUnit. Internal. Runners. junit4classrunner. invoketestmethod (junit4classrunner. Java: 88)
Atorg. JUnit. Internal. Runners. junit4classrunner. runmethods (junit4classrunner. Java: 51)
Atorg. JUnit. Internal. Runners. junit4classrunner $ 1.run( junit4classrunner. Java: 44)
Atorg. JUnit. Internal. Runners. classroadie. rununprotected (classroadie. Java: 27)
Atorg. JUnit. Internal. Runners. classroadie. runprotected (classroadie. Java: 37)
Atorg. JUnit. Internal. Runners. junit4classrunner. Run (junit4classrunner. Java: 42)
Atorg. Eclipse. jdt. Internal. junit4.runner. junit4testreference. Run (junit4testreference. Java: 50)
Atorg. Eclipse. jdt. Internal. JUnit. Runner. testexecution. Run (testexecution. Java: 38)
Atorg. Eclipse. jdt. Internal. JUnit. Runner. remotetestrunner. runtests (remotetestrunner. Java: 467)
Atorg. Eclipse. jdt. Internal. JUnit. Runner. remotetestrunner. runtests (remotetestrunner. Java: 683)
Atorg. Eclipse. jdt. Internal. JUnit. Runner. remotetestrunner. Run (remotetestrunner. Java: 390)
Atorg. Eclipse. jdt. Internal. JUnit. Runner. remotetestrunner. Main (remotetestrunner. Java: 197)
The error message shows that a mock object with this name already exists. This is because the setup method is called once every time a test case is run. We need to give the mock object a different name each time. You can do this.
References:
Http://jmock.org/mocking-classes.html
Http://osdir.com/ml/java.jmock.user/2008-11/msg00049.html
Jmock-use classimposteriser to extend the mock Class Object