我想对一个Android Fragment类进行单元测试。
我是否可以使用AndroidTestCase设置测试,或者我是否需要使用ApplicationTestCase?
有没有关于如何使用这两个TestCase的有用的例子?开发人员站点上的测试例子很少,似乎只关注测试活动。
我在其他地方找到的所有例子都是AndroidTestCase类被扩展的例子,但是所有的测试都是把两个数字加在一起,或者如果使用了上下文,它只是做一个简单的get,并测试某个东西不为空!
根据我的理解,一个Fragment必须存在于一个Activity中,那么我是否可以创建一个模拟Activity,或者让Application或Context提供一个Activity来测试我的Fragment?
我是否需要创建自己的“活动”,然后使用ActivityUnitTestCase?
4条答案
按热度按时间woobm2wo1#
我一直在纠结同样的问题。特别是,由于大多数代码样本已经过时+ Android Studio/SDK正在改进,所以旧的答案有时不再相关。
所以,第一件事:您需要确定是要使用Instrumental测试还是简单的JUnit测试。
它们之间的差别由S.D.here优美地描述;简而言之:JUnit测试更轻量级,不需要仿真器来运行,工具性--给予你最接近实际设备的体验(传感器、GPS、与其他应用程序的交互等)。
1.片段的JUnit测试
比如说,你不需要繁重的仪器测试,简单的junit测试就足够了。我使用了很好的框架Robolectric。
在Gradle中添加:
Mockito、AsserJ是可选的,但我发现它们非常有用,所以我强烈建议也包括它们。
然后在 * 构建变体 * 中,将单元测试指定为 * 测试工件 *:
现在是时候编写一些真实的的测试了:-)作为一个例子,让我们以标准的“Blank Activity with Fragment”样例项目为例。
我添加了一些代码行,以便实际测试:
和类牛:
Robolectic的测试集看起来像这样:
也就是说,我们通过 Robolectric.setupActivity 创建Activity,在test-classes的setUp()中创建新的片段。可选地,您可以立即从setUp()中启动片段,也可以直接从测试中启动。
**NB!**我没有花 * 太 * 多时间在这上面,但是看起来几乎不可能将它与Dagger联系在一起(我不知道Dagger 2是否更容易),因为你不能使用模拟注射设置自定义测试应用程序。
2.碎片的仪器测试
这种方法的复杂性在很大程度上取决于您是否在要测试的应用中使用了Dagger/Dependency注入。
在 * 构建变体 * 中,将Android仪器测试指定为 * 测试工件 *:
在Gradle中,我添加了这些依赖项:
(同样,几乎所有这些都是可选的,但它们可以让你的生活变得轻松得多)
这是一条快乐的道路。与上面的Robolectric的区别只在小细节上。
MainActivityFragment保持不变,如上所述。所以测试集看起来像这样:
正如您所看到的,Test类是 * ActivityInstrumentationTestCase 2 * 类的扩展。此外,非常重要的是要注意 startFragment 方法,与JUnit示例相比,该方法已经发生了变化:默认情况下,测试不在UI线程上运行,我们需要显式调用执行挂起FragmentManager的事务。
这里的事情越来越严重了:-)
首先,我们要去掉 * ActivityInstrumentationTestCase 2 *,而使用 ActivityUnitTestCase 类作为所有片段测试类的基类。
和往常一样,这并不简单,而且有几个陷阱(this就是其中一个例子)。
它有点太长了,所以我把它的完整版本上传到github;
为所有的片段测试创建一个抽象的AbstractFragmentTest:
这里有几件重要的事情。
**1)**我们重写 setActivity() 方法以将AppCompact主题设置为Activity。如果不这样做,测试套件将崩溃。
**2)**setUpActivityAndFragment()方法:
1.调用活动的onCreate();
1.调用活动的onStart();
1.调用活动的onResume();
1.调用片段onAttach();
1.调用片段的onCreateView();
1.调用片段的onStart();
1.调用片段的onResume();
**3)**创建模拟应用程序()方法:与非dagger版本一样,在Pre-step 1中,我们在设备和模拟器上启用了模拟。
然后,我们用我们的定制TestApplication替换注入的普通应用程序!
也就是说,我们向片段提供的不是真实的类,而是它们的模拟版本。(这很容易跟踪,允许配置方法调用的结果,等等)。
而TestApplication只是你的Application的自定义扩展,它应该支持设置模块和初始化ObjectGraph。
**这些是开始编写测试的预备步骤:)**现在是简单的部分,真实的的测试:
**就是这样!**现在您已经为您的片段启用了Instrumental/JUnit测试。
我真诚地希望这篇文章能帮助到一些人。
2izufjch2#
假设您有一个名为“MyFragmentActivity”的FragmentActivity类,其中使用FragmentTransaction添加了一个名为“MyFragment”的公共Fragment类。只需创建一个“JUnit测试用例”类来扩展测试项目中的ActivityInstrumentationTestCase2。然后只需调用getActivity()并访问MyFragment对象及其公共成员来编写测试用例。
请参阅下面的代码片段:
我希望这对你有帮助。如果你觉得这有用,请接受我的回答。谢谢。
3xiyfsfu3#
我很确定你可以做到你所说的,创建一个模拟活动,并从那里测试片段。你只需要导出主项目中的兼容性库,就可以从测试项目中访问片段。我将创建一个示例项目,并在这里测试代码,然后根据我的发现更新我的答案。
有关如何导出兼容性库的详细信息,请查看here。
mwkjh3gx4#
"abhijit.mitkar的回答更是如此。
假设您的片段不是测试活动中的公共成员。
上面代码的目的是用我们可以访问的新片段对象替换该片段。
下面的代码将允许您访问片段UI成员。
从活动中获取UI不会给您带来预期的结果。
最后,如果你想在UI中做一些改变,就像一个好的Android开发人员在主线程中做的那样。
**注意:**您可能希望在每次测试结束时为其给予一个Thread.sleep().为了避免锁定,getInstrumentation().waitForIdleSync();似乎并不总是有效。
我使用了ActivityInstrumentationTestCase 2,因为我正在进行功能测试。