JMockit gives mockit.internal.UnexpectedInvocation when I try to instrument the code with clover.

I have tests that use jmockit and when I try to instrument it using Clover I get the following exception:

mockit.internal.UnexpectedInvocation: Unexpected invocation of:
java.io.File#File(String)

 with arguments: 
"C:\git\ng-cloud\tools\appfabric\maven\package-code-scan-plugin\.clover\coverage.db1f6pnu9s8ffmg_1_an8s56_i907uj4k.s"
 on mock instance: java.io.File@683a412e
 at java.io.File.<init>(File.java)
 at com.atlassian.clover.recorder.FileBasedPerTestRecording.<init>(FileBasedPerTestRecording.java:33)
 at com.atlassian.clover.recorder.FileBasedPerTestRecording.<init>(FileBasedPerTestRecording.java:51)
 at com.atlassian.clover.recorder.ActivePerTestRecorderOne.testFinished(ActivePerTestRecorderOne.java:67)
 at com.atlassian.clover.recorder.ThreadVisibilityStrategy$SingleThreaded.testFinished(ThreadVisibilityStrategy.java:119)
 at com.atlassian.clover.recorder.BaseCoverageRecorder.sliceEnd(BaseCoverageRecorder.java:376)
 at com_atlassian_clover.Clover$InitialisedRuntime$4.run(Clover.java:675)
 at com_atlassian_clover.Clover$InitialisedRuntime$4.run(Clover.java:668)
 at java.security.AccessController.doPrivileged(Native Method)
 at com_atlassian_clover.Clover$InitialisedRuntime.allRecordersSliceEnd(Clover.java:668)
 at com_atlassian_clover.Clover.allRecordersSliceEnd(Clover.java:144)
 at com.atlassian.clover.recorder.BaseCoverageRecorder.globalSliceEnd(BaseCoverageRecorder.java:137)
 at com.org.application.maven.DirectoryScannerTest.verifyDirectoryExistsNullFiles(DirectoryScannerTest.java:131)

 

My test code is as follows:

@Test
 public void verifyDirectoryExistsSuccess(@Mocked final List<File> filesToVerify,
 @Mocked final File file,
 @Mocked final Iterator it) throws IllegalArgumentException {final File[] files = new File[1];
new Expectations() {{
 filesToVerify.isEmpty(); result = Boolean.FALSE; times = 1;
 filesToVerify.iterator(); result = it; times = 1;
 it.hasNext(); result = Boolean.TRUE; times = 1;
 it.next(); result = file; times = 1;
 file.exists(); result = Boolean.TRUE; times = 1;
 it.hasNext(); result = Boolean.FALSE; times = 1;
 }};
 final DirectoryScanner ds = new DirectoryScanner(null, "filetest", null);
 assertEquals(1, ds.verifyDirectoriesExist(filesToVerify).size());
 }

1 answer

1 accepted

1 votes

Hi Vinayak,

I think I've figured it out. There are several issues in your code sample.

 

1) Special handling of Expectations / Verifications blocks by JMockit.

The following example when instrumented by Clover:

@Test
public void doFileNoCloverOff() throws Exception {
    new Expectations() {{

    }};
}

fails with an error message:

doFileNoCloverOff(MyFileTest)  Time elapsed: 0.327 sec  <<< ERROR!
java.lang.IllegalArgumentException: Invalid try/finally statement inside expectation block
        at MyFileTest$1.<init>(MyFileTest.java)
        at MyFileTest.__CLR4_0_4k5yzrl1z(MyFileTest.java:16)
        at MyFileTest.doFileNoCloverOff(MyFileTest.java:15)

 

Clover adds it's own instrumentation code inside the Expectations block (as it sees it as a normal instance initializer). At the same time JMockit treats code inside the Expectations block in a special way - not as a regular code, but as a list of expected invocations.

You have to disable Clover instrumentation for the Expectations block - surround it with ///CLOVER:OFF and ///CLOVER:ON comments, as it was described here:

https://answers.atlassian.com/questions/12273406

 

2) Using full mocks for classes from JDK

The following example when instrumented by Clover:

@Test
public void doFileFullMock(@Mocked final File file) throws Exception {
    final File someFile = new File("C:\\Temp");

    ///CLOVER:OFF
    new Expectations() {{
        someFile.getAbsolutePath(); result = "XYZ";
    }};
    ///CLOVER:ON

    assertEquals("XYZ", someFile.getAbsolutePath()); // calls mocked method
}

compiles and test succeeds, but Clover fails with an error like this:

ERROR: CLOVER: Unable to load the coverage database at "null"
ERROR: CLOVER: No coverage data will be gathered.

 

It fails because your test is mocking java.io.File class, which is being used by Clover to write code coverage file to disk. Due to a fact that full mock is used, all methods of the mocked class return null value, unless they are specified in the Expectations block.

 

In order to fix this you have to use a partial mock, so that original methods will be called (unless specified in the Expectations block).

 

@Test
public void doFilePartialMock() throws Exception {
    final File someFile = new File("C:\\Temp");

    ///CLOVER:OFF
    new Expectations(File.class) {{ // a partial mock
        someFile.getAbsolutePath(); result = "XYZ";
    }};
    ///CLOVER:ON

    assertTrue(someFile.exists()); // calls original method
    assertEquals("XYZ", someFile.getAbsolutePath()); // calls mocked method

    // when instrumented, Clover calls its own code here, 
    // which writes per-test coverage file to disk
}

 

See http://jmockit.org/tutorial/BehaviorBasedTesting.html#partial

 

Cheers
Marek

I made the changes as you had suggested but I am having no luck when I do clover2:instrument.By the way I am using java 7.

Can you confirm that you've added "new File(anyString); minTimes = 0;" too?

What error message do you see? What flush policy settings do you use? What JMockit version do you use? I'm asking because I've noticed a slightly different behaviour than described by you.

I have added new File(anyString); minTimes = 0 and the tags to switch off and on clover for expectation block.But still I get the invocation error.Here is the stacktrace: erifyDirectoryExistsSuccess(com.org.app.maven.DirectoryScannerTest) Time elapsed: 0.019 sec <<< ERROR! mockit.internal.UnexpectedInvocation: Unexpected invocation of: java.io.File#File(String) with arguments: "C:\git\next\tools\app\maven\package-code-scan-plugin\target\clover\clover.dbru9c6j24nagh_1j_vkgrxe_i91d1n4n.s" on mock instance: java.io.File@101b57f7 at java.io.File.<init>(File.java) at com.atlassian.clover.recorder.FileBasedPerTestRecording.<init>(FileBasedPerTestRecording.java:33) at com.atlassian.clover.recorder.FileBasedPerTestRecording.<init>(FileBasedPerTestRecording.java:51) at com.atlassian.clover.recorder.ActivePerTestRecorderMany.testFinished(ActivePerTestRecorderMany.java:45) at com.atlassian.clover.recorder.ThreadVisibilityStrategy$SingleThreaded.testFinished(ThreadVisibilityStrategy.java:119) at com.atlassian.clover.recorder.BaseCoverageRecorder.sliceEnd(BaseCoverageRecorder.java:376) at com_atlassian_clover.Clover$InitialisedRuntime$4.run(Clover.java:675) at com_atlassian_clover.Clover$InitialisedRuntime$4.run(Clover.java:668) at java.security.AccessController.doPrivileged(Native Method) at com_atlassian_clover.Clover$InitialisedRuntime.allRecordersSliceEnd(Clover.java:668) at com_atlassian_clover.Clover.allRecordersSliceEnd(Clover.java:144) at com.atlassian.clover.recorder.BaseCoverageRecorder.globalSliceEnd(BaseCoverageRecorder.java:137) at com.org.app.maven.DirectoryScannerTest.verifyDirectoryExistsSuccess(DirectoryScannerTest

Please try to recompile your code. I've been running some tests and found a workaround for a mocked File class. See my updated answer.

Suggest an answer

Log in or Join to answer
Community showcase
Teodora [Botron]
Published Thursday in Marketplace Apps

Jira Inferno: The Nine Circles of Jira Administration Hell

If you spend enough time as a Jira admin - whether you are managing a single, mid-sized instance, a large enterprise one or juggling multiple instances at once - you will eventually find yourself in ...

973 views 5 18
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you
Atlassian Team Tour

Join us on the Team Tour

We're bringing product updates and pro tips on teamwork to ten cities around the world.

Save your spot