New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test fails after enabling feature for mocking final classes and methods #1005
Comments
@geralt-encore Could you build a gist so that we can easily test it? I am not familiar with the Android ecosystem, would like to have a quick install to debug directly. |
Here is a sample project for reproduction: https://github.com/geralt-encore/MockitoBug |
I have assigned @raphw, as he is probably the most knowledgeable about this bug. However, he is quite busy IRL so it might take some time before he is able to respond. Thanks for your understanding! |
Sure! Let me know if you need more info from me. |
I do not currently have an Android SDK installed but I assume it has something to do with your use of Android? The inline mock maker requires running on a "regular" JVM and cannot be used on Android or on an emulator. |
@raphw, I am interested in this issue and I investigated this with the above reproducible project. I suppose this is a bug of byte-buddy. Running the code above causes ArrayIndexOutOfBoundsException. Here is the stack trace elements.
The exception has occurred here. I set a breakpoint at the place where the exception occurred.
Since the length of the array
The stack map table has two entries. Moreover I ran the following code. package com.geraltencore.mockitobug;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import net.bytebuddy.jar.asm.ClassReader;
import net.bytebuddy.jar.asm.ClassVisitor;
import net.bytebuddy.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Opcodes;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Arrays;
public class MyTest {
private static final String[] TYPE_NAMES = {
"F_NEW",
"F_FULL",
"F_APPEND",
"F_CHOP",
"F_SAME",
"F_SAME1",
};
@Test
public void test() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = getClass().getResourceAsStream('/' + GoogleSignInAccount.class.getName().replace('.', '/') + ".class");
try {
byte[] buffer = new byte[8192];
for (int l; (l = in.read(buffer)) != -1; ) {
out.write(buffer, 0, l);
}
} finally {
in.close();
}
new ClassReader(out.toByteArray()).accept(new ClassVisitor(Opcodes.ASM5) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
return name.equals("getAccount") ? new MethodVisitor(api, mv) {
private int n = 0;
@Override
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
super.visitFrame(type, nLocal, local, nStack, stack);
System.out.println("#" + n++);
System.out.println(" type=" + TYPE_NAMES[type + 1]);
System.out.println(" nLocal=" + nLocal);
System.out.println(" local=" + Arrays.toString(local));
System.out.println(" nStack=" + nStack);
System.out.println(" stack=" + Arrays.toString(stack));
}
} : mv;
}
}, 0);
}
} Here is the result.
Let me know if you need more information. |
As @tmurakami pointed I am not running this test on Android - it occurs on regular JVM. |
@ChristianSchwarz, I think this is not Android specific problem. The issue #939 and #978 are that |
This is an interesting error. The problem is the full frame that does not specify any local variables. This is incorrect for the method in question which is non-static and should therefore always specify a 'this' value. The compiler that created this method apparently voided this variable. As a consequence, Byte Buddy cannot longer instrument the method as it requires access to the "this" reference even after the method return which has now become impossible. That the error is suppressed is unfortunate and we need to improve this. The error itself can however not be fixed as the stack map frames are already corrupted. It would be interesting to know how these frames got in there. Creating the same class and compiling it with javac yields correct frames. |
…to mock maker that attempts instrumentation. Addresses #1005
@raphw, thank you for your reply.
@geralt-encore, I tried using android {
testOptions {
unitTests.all {
jvmArgs '-noverify'
}
}
} |
@tmurakami I just tried it and it didn't work. Did I miss something? Looks pretty straightforward. |
Add the apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.geraltencore.mockitobug"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
testOptions {
unitTests.all {
jvmArgs '-noverify'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.0'
compile 'com.google.android.gms:play-services-auth:10.2.1'
testCompile 'org.mockito:mockito-core:2.7.19'
testCompile 'junit:junit:4.12'
} Then, run Here is my Java environment:
If you run test on Android Studio, set |
I see, ran it from Android Studio and forgot that it won't use options specified in Gradle. Are there any downsides of using it? |
|
The Android Framework Team is going to provide better mock support with |
@ChristianSchwarz, thank you for your information. Generally, an Android project has two kinds of tests.
That PR seems to provide inline mocking feature on Android VM using slicer library. On the other hand, this problem occurs while running local unit tests, so unfortunately that PR will not help this issue. |
I'm trying to run the Instrument Test and getting the following error: org.mockito.exceptions.base.MockitoException:
The build.gradle file includes the following dependencies {
} |
I am mocking GoogleSignInAccount with the latest Mockito version:
After enabling mocking of final classes/methods test fails with this error (which is not really helpful):
Let me know if you need more details from me.
The text was updated successfully, but these errors were encountered: