15

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

我已经阅读了活动测试教程测试基础部分。那里所说的大部分内容只有在您要测试要测试的项目中已经存在的活动时才有意义。但我只需要一个模拟的来做一些事情,比如在 Ui 线程中显示对话框和运行短任务。

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


更新
由于我没有找到任何自动创建模拟活动的方法,我决定自己提供它。我在测试项目中创建了一个什么都不做的虚拟活动,并通过 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 测试框架在启动 Activity 时遇到了问题,并且出现了以下异常:

        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)

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

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

4

3 回答 3

8

使用 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
    }
}
于 2020-03-06T13:11:50.377 回答
6

解决了!这是我所做的:

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

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

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

于 2012-10-24T09:16:07.617 回答
0

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

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

带有自定义意图

    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()您可以通过方法访问场景界面。您可以在测试中手动完成您的活动,它不会导致任何问题,并且在这种情况下测试后此规则不会执行任何操作。

于 2021-02-25T18:01:45.787 回答