jmockit1
jmockit1 copied to clipboard
java.lang.ClassCastException: java.lang.Class cannot be cast to {Mock method return type}
Please provide the following information:
-
Version of JMockit that was used: 1.35 and 1.49
-
Description of the problem or enhancement request: from time to time, we get a "java.lang.ClassCastException: java.lang.Class cannot be cast to {Mock method return type}" on either a local variable initialization or a method call argument. I couldn't yet determine a specific deterministic use case.
Do you have a code example? What do you use MockUp
or @Injectable
etc?
I'm in an effort of fixing this flaky symptom over a couple of tests. It happens on Mocked
and Injectable
references, much more frequent on Injectables
, I've a couple of comments on the code stating that they had mocked it using Mockup
s due to issues using Expectations
but with no further details.
One of the cases we can put it like this:
public void someTestMoethod(@Mocked final Dependency1 dependency1) {
final long id = dependency1.getId(); // <<--- rarely it throws "java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.Long"
}
It occurs both with or without an expectation. The machine has it's CPU exhausted running the test in parallel, process forked per class, and executing sequentially over the class.
I'm looking into the source code trying to make sense of it. I spotted this exception (on a passing test) on a scheduled task that continues after the test case, this I think to be related to the mocking being "cleanup" upon the test case finishes. Also, as far as I understood, since the mocking structures aren't synchronized, we must not create expectations using multiple threads, at least without the proper synchronization.
Even so, I still can make sense of it on the case shown above.
Much appreciated your help, even if you can only guide me on where to look for on the code.
Narrowing down a little bit more with additional details:
interface Dependency1Interface {
Identifier getId();
}
class Dependency1 implements Dependency1Interface {}
public void someTestMethod(@Mocked final Dependency1 dependency1) {
final Identifier id = dependency1.getId(); // <<--- rarely it throws "java.lang.ClassCastException: java.lang.Class cannot be cast to com.foo.Identifier"
}
So far I managed to reverse engineer the getId()
redefined method into the following:
public getId()Ljava/foo/Identifier;
ALOAD 0
LDC 1025
LDC "com/foo/Dependency1Interface"
LDC "getId()Lcom/foo/Identifier;"
ACONST_NULL
LDC 0
ACONST_NULL
INVOKESTATIC mockit/internal/expectations/RecordAndReplayExecution.recordOrReplay (Ljava/lang/Object;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/Object;)Ljava/lang/Object;
CHECKCAST com/foo/Identifier
ARETURN
MAXSTACK = 7
MAXLOCALS = 1
Seems to me that this CHECKCAST com/foo/Identifier
is the source of the exception.
If that's true, that mean the Class
instance is being returned by the RecordAndReplayExecution.recordOrReplay
.
Adding up on the findings...
I spotted that within certain circumstances, like the case where a task continues to run after the end of the test case, the RecordAndReplayExecution.recordOrReplay
returns Void.class
, so, this Void.class
's must be on the root of the exception being thrown, now, on the getId()
scenario I can't figure out why it fails from time to time...
Why hasn't this problem been fixed yet?