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 vote

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 Sign up to answer
How to earn badges on the Atlassian Community

How to earn badges on the Atlassian Community

Badges are a great way to show off community activity, whether you’re a newbie or a Champion.

Learn more
Community showcase
Published yesterday in Confluence

Three common content challenges + how to manage them

An efficient enterprise content management system, or ECM, is a must-have for companies that create work online (cough   cough, all companies). If content calendars, marketing plans, and bu...

53 views 0 4
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