创建模拟Activity以进行测试的最快方法

时间:2012-10-23 16:30:40

标签: android unit-testing mocking android-activity

我目前正在对图书馆进行单元测试。在某些类中,我需要在一些静态方法中将活动作为参数传递。图书馆本身不包含任何活动。我需要以某种方式获取模拟活动的实例,以便在每个单独的方法测试中使用。

我已阅读Activity Testing TutorialTesting Fundamentals部分。如果你要测试已经存在于待测试项目中的活动,那么它的大部分内容才有意义。但我只需要一个模拟器来做一些事情,比如在Ui线程中显示对话框和运行短任务。

实现这一目标的最快,最简单的方法是什么?我应该在我的测试项目中创建模拟活动,还为虚拟UI提供xml布局资源?


UPDATE
由于我没有找到任何自动创建模拟活动的方法,所以我决定自己提供。我在测试项目中创建了一个虚拟活动,什么都不做,并通过xml提供了一个虚拟布局。然后我将我的测试编码为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");
        }
    }

MockActivity是我在此测试项目中创建的上述模拟活动。但是,似乎Android测试框架在启动活动时遇到了问题,并且出现了这个异常:

        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)

现在我完全迷失在这里。怎么会这么复杂?我选择了正确的方法吗?我只想在测试方法中启动一个对话框。也许框架搞乱了,因为要测试的活动不在目标项目中?

这里的任何帮助将不胜感激。我已经没时间了,如果找不到合适的方法,我必须使用我的库创建第二个项目,在那里移动模拟活动并从测试项目进行测试。这是很多代码,因为我必须在(现在不是通用的)模拟活动中包含一个方法来调用我想要测试的每个库方法。

3 个答案:

答案 0 :(得分:5)

使用androidX库,您可以使用ActivityScenario。 只需将androidTestImplementation("androidx.test:core:1.2.0")导入到您的app.gradle文件中

然后,在您的检测测试中,导入ActivityScenario并使用以下命令启动活动:

import androidx.test.core.app.ActivityScenario

@Test
fun testActivity() {
    ActivityScenario.launch(MainActivity::class.java).onActivity { activity ->
        // do something with your activity instance
    }
}

答案 1 :(得分:4)

解决!这是我做的:

  • 在测试项目中,我在检测选项卡中删除了目标包,并再次添加它指向模拟活动所在的测试项目基础包。
  • 在我的测试项目中将目标库添加为Android库。 (右键单击测试项目 - &gt;属性 - &gt; Android - &gt;库 - &gt;添加目标库)。
  • 在测试项目清单中添加了模拟活动。
  • 要解决我上面发布的异常,只需用以下代码替换测试用例构造函数:

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

现在可行,我可以成功启动对话框。但在我的简短研究中,我偶然发现Robotium。这个图书馆真是太棒了。我一开始并不需要它,但我发现以自动方式测试GUI非常有用。现在,我在每个setUp调用中重新创建了一个全新的活动。

答案 2 :(得分:0)

ActivityScenario 提供 API 来启动和驱动 Activity 的生命周期状态以进行测试。它适用于任意活动,并在不同版本的 Android 框架中始终如一地工作。

val scenario = launchActivity<MyActivity>()
scenario.onActivity { activity ->  
// do some stuff with the Activity
}

带有自定义 Intent

    val intent = Intent(ApplicationProvider.getApplicationContext(), MyActivity::class.java)
    .putExtra("title", "Testing rules!")
   val scenario = launchActivity<MyActivity>(intent)
    scenario.onActivity { activity ->  
    // do some stuff with the Activity
}

ActivityScenarioRule 在测试开始前启动给定的活动,并在测试后关闭。 您可以通过 getScenario() 方法访问场景界面。您可以在测试中手动完成您的活动,它不会导致任何问题,并且在这种情况下,此规则在测试后没有任何作用。