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()); }
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
Can you confirm that you've added "new File(anyString); minTimes = 0;" too?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.