Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test Activity onCreate Exception

I have the following Activity that throws an exception if something is configured wrong.

public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        throw new IllegalStateException("something went wrong");
    }
}

I tried to write a test for this ActivityInstrumentationTestCase2

public void testException() throws Exception {
    try {
        getActivity().onCreate(null);
        fail();
    } catch (IllegalStateException e) {
        assertThat(e.getMessage()).contains("something went wrong");
    }
}

which throws the correct Exception but doesn't run in my catch block due to some internal Sandboxing of the ActivityInstrumentationTestCase2.

So I tried it with plain Java

public void testException() throws Exception {
    final MockNavigationDrawerActivity activity = Mockito.mock(MockNavigationDrawerActivity.class);
    Mockito.doCallRealMethod().when(activity).onCreate(null);
    try {
        activity.onCreate(null);
        fail();
    } catch (IllegalStateException e) {
        assertThat(e.getMessage()).contains("something went wrong");
    }
}

which does not work

java.lang.AbstractMethodError: abstract method "boolean org.mockito.internal.invocation.AbstractAwareMethod.isAbstract()"
at org.mockito.internal.invocation.InvocationImpl.callRealMethod(InvocationImpl.java:109)
at org.mockito.internal.stubbing.answers.CallsRealMethods.answer(CallsRealMethods.java:41)
at org.mockito.internal.stubbing.StubbedInvocationMatcher.answer(StubbedInvocationMatcher.java:34)
at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:91)
at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:38)
at com.google.dexmaker.mockito.InvocationHandlerAdapter.invoke(InvocationHandlerAdapter.java:49)
at MockNavigationDrawerActivity_Proxy.onCreate(MockNavigationDrawerActivity_Proxy.generated)

Any idea how to test this simple case?

Update #1

I tried absolutely everything. I reduced it to the absolute minimum which doesn't work.

public void testUpdate1() throws Exception {
    try {
        getActivity();
        fail();
    } catch (Exception e) {
        assertThat(e.getMessage()).contains("something went wrong");
    }
}

stacktrace:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.MyActivity}: java.lang.IllegalStateException: something went wrong
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
        at android.app.ActivityThread.access$800(ActivityThread.java:144)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
        Caused by: java.lang.IllegalStateException: something went wrong
        at com.example.MyActivity.onCreate(MyActivity.java:28)
        at android.app.Activity.performCreate(Activity.java:5933)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
        at android.support.test.runner.MonitoringInstrumentation.callActivityOnCreate(MonitoringInstrumentation.java:346)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
        ... 10 more

Update #2

I started from the beginning. Generated a new project, threw the Exception

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    throw new IllegalStateException("something");
}

an tried to catch it with a Throwable.

public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {

    public MainActivityTest() {
        super(MainActivity.class);
    }

    public void testOnCreate() throws Exception {
        try {
            getActivity();
            fail();
        } catch (Throwable throwable) {
            assertTrue(throwable.getCause().getMessage().contains("something"));
        }

    }
}

I got this (complete) stacktrace which does not lead to my test. The system seems to call onCreate, perhaps from a different process, not my test.

Process: com.pascalwelsch.onccreatetest, PID: 3915    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.pascalwelsch.onccreatetest/com.pascalwelsch.onccreatetest.MainActivity}: java.lang.IllegalStateException: something
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
        at android.app.ActivityThread.access$800(ActivityThread.java:144)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
 Caused by: java.lang.IllegalStateException: something
        at com.pascalwelsch.onccreatetest.MainActivity.onCreate(MainActivity.java:15)
        at android.app.Activity.performCreate(Activity.java:5933)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
            at android.app.ActivityThread.access$800(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
like image 740
passsy Avatar asked May 13 '15 14:05

passsy


People also ask

What is onCreate () meant for?

onCreate() It is called when the activity is first created.

Is onCreate only called once?

OnCreate is only called once.

Why onCreate is called twice?

onCreate will get called when your activity has been destroyed and recreated, which happens any time the device is rotated, the keyboard is opened, or you switch apps and the system decides it's time to reclaim some memory and kill off your app.

What is the purpose of onCreate () function in Android?

onCreate(Bundle savedInstanceState) Function in Android: After Orientation changed then onCreate(Bundle savedInstanceState) will call and recreate the activity and load all data from savedInstanceState. Basically Bundle class is used to stored the data of activity whenever above condition occur in app.


2 Answers

You are throwing IllegalArgumentException and catching IllegalStateException. You can add another catch block with catching Exception - it will work.

like image 122
Ircover Avatar answered Sep 27 '22 22:09

Ircover


Why do you mock the class you are trying to test? You should mock dependencies of MyActivity to test that its methods are correctly using the mocks.

For example if you want to test class A which depends on B and C, then you want to create 2 mocks for B and C and a concrete object of A. Then you inject those 2 mocks in your object and you can start calling methods on it.

This is probably also the reason you get a java.lang.AbstractMethodError (there is not enough code posted to confirm it though). If you call a real method on a mock, whereas this method is abstract (for example you are mocking an interface or abstract class), then this error is thrown.

Below I posted some code and a test as example of how you can insert mocks into a concrete object.

In code:

class A {
  B b;
  C c;

  void doSomething() {
    b.aMethod();
    c.anotherMethod();
    throw new IllegalArgumentException("something went wrong");
  }
}
interface B {
  void aMethod();
}
abstract class C {
  void anotherMethod();
}

with a test:

@RunWith(MockitoJUnitRunner.class)
class ATest {
  @Mock B b;
  @Mock C c;
  // The inject mocks will insert both b and c into a by using reflection
  @InjectMocks A a;

  @Test(expected=IllegalArgumentException.class)
  public void testSomething() {
    a.doSomething();
  }
}
like image 21
Tim van der Lippe Avatar answered Sep 27 '22 21:09

Tim van der Lippe