Fastest way to create a mock Activity for testing

11,981

Solution 1

Solved! Here's what I did:

  • In the test project, I removed the target package in the instrumentation tab and added it again pointing to the test project base package, where the mock activity is.
  • Added the target library as an Android Library in my test project. (Right click over test project -> properties -> Android -> Library -> added the target library).
  • Added the mock activity in the test project manifest.
  • To solve the exception I posted above, just replaced the test case constructor with this one:

        public LibraryTest() {
            super(MockActivity.class);
        }
    

Now that works and I can successfully launch dialogs. But in my brief research I stumbled upon Robotium. This library is just amazing. It is not needed for what I was trying to do at first, but I found it very useful to test GUIs in an automated way. Now I have a fresh new activity recreated in each setUp call.

Solution 2

With androidX libraries, you can use ActivityScenario. Simply import androidTestImplementation("androidx.test:core:1.2.0") in your app.gradle file

Then, in your instrumented test, import ActivityScenario and launch the activity with:

import androidx.test.core.app.ActivityScenario

@Test
fun testActivity() {
    ActivityScenario.launch(MainActivity::class.java).onActivity { activity ->
        // do something with your activity instance
    }
}
Share:
11,981
Mister Smith
Author by

Mister Smith

Android freak, but still a noob.

Updated on June 17, 2022

Comments

  • Mister Smith
    Mister Smith about 2 years

    I'm currently unit-testing a library. In certain classes, I need to pass an activity as parameter in some static methods. The library itself contains no activities. I need to somehow obtain an instance of a mock activity to use in each individual method test.

    I've already read the Activity Testing Tutorial and the Testing Fundamentals section. Most of what it is said there only makes sense if you are about to test Activities already existing in the project to be tested. But I just need a mock one to do things like showing dialogs and run short tasks in the Ui thread.

    What would the fastest, simplest way to achieve this? Should I create the mock activity in my test project and also provide xml layout resources for the dummy UI?


    UPDATE
    Since I've not found any way of creating a mock activity automatically I decided to provide it by myself. I've created inside the test project a dummy activity doing nothing and provided a dummy layout via xml. Then I coded my test extending ActivityInstrumentationTestCase2:

        public class LibraryTest extends ActivityInstrumentationTestCase2<MockActivity> {
    
            public LibraryTest(String name) {
                super(MockActivity.class);
            }
    
            protected void setUp() throws Exception {
                super.setUp();
            }
    
            public void testAMethodFromLibrary() {
                fail("Not yet implemented");
            }
        }
    

    Where MockActivity is the aforementioned mock activity I've created in this test project. However, seems that the Android test framework is having trouble launching the activity and it comes up with this exception:

            java.lang.RuntimeException: Exception during suite construction
            at android.test.suitebuilder.TestSuiteBuilder$FailedToCreateTests.testSuiteConstructionFailed(TestSuiteBuilder.java:239)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
            at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
            at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:520)
            at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
            Caused by: java.lang.NullPointerException: Method name must not be null.
            at java.lang.ClassCache.findMethodByName(ClassCache.java:297)
            at java.lang.Class.getMethod(Class.java:985)
            at android.test.suitebuilder.TestMethod.getAnnotation(TestMethod.java:60)
            at android.test.suitebuilder.annotation.HasMethodAnnotation.apply(HasMethodAnnotation.java:39)
            at android.test.suitebuilder.annotation.HasMethodAnnotation.apply(HasMethodAnnotation.java:30)
            at com.android.internal.util.Predicates$OrPredicate.apply(Predicates.java:106)
            at android.test.suitebuilder.annotation.HasAnnotation.apply(HasAnnotation.java:42)
            at android.test.suitebuilder.annotation.HasAnnotation.apply(HasAnnotation.java:31)
            at com.android.internal.util.Predicates$NotPredicate.apply(Predicates.java:122)
            at android.test.suitebuilder.TestSuiteBuilder.satisfiesAllPredicates(TestSuiteBuilder.java:254)
            at android.test.suitebuilder.TestSuiteBuilder.build(TestSuiteBuilder.java:190)
            at android.test.InstrumentationTestRunner.onCreate(InstrumentationTestRunner.java:373)
            at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4218)
            at android.app.ActivityThread.access$3000(ActivityThread.java:125)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2071)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:123)
            at android.app.ActivityThread.main(ActivityThread.java:4627)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
            at dalvik.system.NativeStart.main(Native Method)
    

    Now I'm totally lost here. How can this be so complicated? Have I chosen the correct way? I just want to launch a dialog in a test method. Maybe the framework is messing up because the activity to test is not in the target project?

    Any help here would be much appreciated. I'm getting out of time and if I can't find the proper way to do this I'd have to create a second project using my library, move the mock activity there and test from the test project. This is a lot of code because I'd have to include a method in a (now not generic) mock activity just to call every library method I want to test.

  • IgorGanapolsky
    IgorGanapolsky over 3 years
    How does this create a mock of the Activity?
  • Nicola Gallazzi
    Nicola Gallazzi over 3 years
    @IgorGanapolsky actually this isn't a proper mocking, it doesn't run in the JVM but it's a fast way to test an activity in isolation. Probably I should clarify my answer. Thank you for your advice