Mockito @InjectMocks broken #2442

Closed
floating-cat opened this Issue May 5, 2016 · 4 comments

Projects

None yet

3 participants

@floating-cat

Description

java.lang.ClassCastException: Cannot cast android.widget.TextView$MockitoMock$809592802 to org.robolectric.shadows.ShadowActivity

    at java.lang.invoke.MethodHandleImpl.newClassCastException(MethodHandleImpl.java:361)
    at java.lang.invoke.MethodHandleImpl.castReference(MethodHandleImpl.java:356)
    at android.app.Activity.finish(Activity.java)
    at com.example.SimpleTest.test(SimpleTest.java:36)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:531)

Steps to Reproduce

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
public class SimpleTest {
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Mock
    TextView textView;

    @InjectMocks
    Activity activity = Robolectric.setupActivity(FragmentActivity.class);

    @Test
    public void test() {
        activity.finish();
    }
}

This snippet doesn't work and always throw ClassCastException. If I remove @Mock annotation or remove activity.finish() or change FragmentActivity.class to Activity.class, this snippet works.

Robolectric & Android Version

Robolectric 3.1-rc1.
compileSdkVersion 23.

I also test this code in Robolectric 3.0, it throws java.lang.IllegalArgumentException: attempted to invoke public void org.robolectric.shadows.ShadowActivity.finish() on instance of class android.widget.TextView$MockitoMock$619060240, but TextView$MockitoMock$619060240 doesn't extend ShadowActivity.

I struggle this problem all day and still have no idea><, If you want other information, I am also glad to provide.

Thanks.

@jongerrish
Contributor

Just guessing but I wonder if the JUnit rule has applied @InjectMocks to the ShadowActivity that has been attached by Robolectric though byte code injection to the real Activity?

@floating-cat

@InjectMocks can inject dependencies into the real Activity. But I don't know whether

JUnit rule has applied @InjectMocks to the ShadowActivity that has been attached by Robolectric though byte code injection to the real Activity.

I also found that I can invoke some methods in Activity like Activity#onOptionsItemSelected(Menu) and Activity#getIntent(), but I can't invoke some methods which have a implementation in ShadowActivity like Activity#finish() and Activity#isFinishing().

@floating-cat floating-cat changed the title from `@Mock` (from Mockito) doesn't work well with Robolectric to Mockito doesn't work well with Robolectric May 6, 2016
@jongerrish
Contributor

Just a side note, but I highly recommend against mocking Android framework classes, especially views and contexts. This is because the internal workings of Android can change across versions and upgrading APIs may require changes in stubbing behaviour. In your example using a real TextView would be better. The one exception I would make is for simple listener/callback classes that you want to verify got called.

@floating-cat
floating-cat commented May 20, 2016 edited

Thanks for your advice. Actually I mocked a class written by myself. But when I wrote that test example to show this issue, I mocked the TextView because TextView is so common in Android and I wrote that code without thinking too much.
I must admit I wrote a bad test example, and now I learn from it. I will write a better test example if I have more chances somewhere.
You are right, I should not mock it. I recall I read a testing book tells my not to mock some dependencies from others and mock something you write.

Thank your very much.

edit: fix some typos.

@xian xian closed this Jan 5, 2017
@xian xian reopened this Jan 5, 2017
@xian xian changed the title from Mockito doesn't work well with Robolectric to Mockito @InjectMocks broken Jan 5, 2017
@xian xian referenced this issue Jan 5, 2017
Merged

Fix @InjectMocks. #2820

@xian xian closed this in #2820 Jan 6, 2017
@xian xian added this to the 3.2.1 milestone Jan 6, 2017
@xian xian added the defect label Jan 6, 2017
@xian xian self-assigned this Jan 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment