Thursday, March 21, 2013

Eclipse and JMockit: Method should have no parameters

I am testing out JMockit in Eclipse and I find an error I didn't expect with my very first test. I am using jmockit-1.1, JUnit 4, Java SE 1.7, Juno Service Release 1.

I have the following code as a jUnit test in Eclipse.

package rmb.budget.reader;

import mockit.Mocked;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class TestReader {
  @Test
  public void testReader(
      @Mocked MyReader reader) {
  }
}
When I run this, I get the below error.
java.lang.Exception: Method testReader should have no parameters
  at org.junit.runners.model.FrameworkMethod.validatePublicVoidNoArg(FrameworkMethod.java:69)
  at org.junit.runners.ParentRunner.validatePublicVoidNoArgMethods(ParentRunner.java:131)
  at org.junit.runners.BlockJUnit4ClassRunner.validateTestMethods(BlockJUnit4ClassRunner.java:178)
  at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:163)
  at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:102)
  at org.junit.runners.ParentRunner.validate(ParentRunner.java:344)
  at org.junit.runners.ParentRunner.(ParentRunner.java:74)
  at org.junit.runners.BlockJUnit4ClassRunner.(BlockJUnit4ClassRunner.java:55)
  at org.junit.runners.JUnit4.(JUnit4.java:20)
  at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
  at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
  at java.lang.reflect.Constructor.newInstance(Unknown Source)
  at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:31)
  at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24)
  at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
  at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)
  at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
  at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.(JUnit4TestReference.java:33)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.(JUnit4TestClassReference.java:25)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:48)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

My understanding from the JMockit Getting Started page is that it very definitely should be possible to use (mocked) parameters in @Test methods.

import org.junit.*;
import mockit.*;

public class MyFirstJMockitTest {
   @Test
   public void testMethodWithMockParameter(
         @Mocked YetAnotherDependency testSpecificMock) {
   }
}

I raised a bug report but was soon put right by the JMockit developer, Rogerio Liesenfeld. I had two things wrong.

  • In your .classpath file, the JMockit jar must appear before JUnit. For example.
    <classpathentry kind="lib" path="lib/jmockit-1.1.jar"/>
    <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
    
  • I was using the vanilla JRE in my project, which fails if you don't use the -javaagent JVM parameter. I found it easier to swap over to a JDK version of Java SE instead (which you can get from the Oracle Java SE download page). I already had it installed - what Java developer wouldn't? (This resulted from having just made my Eclise Java project with default options selected in a newly created workspace.) So now I was using a proper JDK in my project.
    Use a JDK for development in Eclipse, not a vanilla JRE.