如何防止ActivityUnitTestCase调用Application.onCreate?

Mat*_*ias 18 android unit-testing

我必须在这里遗漏一些东西.JavaDoc ActivityUnitTestCase建议此测试用例与系统隔离测试一个Activity:

此类提供单个活动的独立测试.将使用与系统基础结构的最小连接来创建测试中的活动,并且可以注入许多Activity的依赖项的模拟或包装版本.

我假设包括没有实际启动应用程序.此外,它暴露了setApplication一个可以用来注入模拟应用程序的助手.

但是,任何ActivityUnitTestCase我开始启动(实际)应用程序并调用其onCreate方法.更准确地说,InstrumentationTestRunner似乎是这样做,甚至在我有机会进入setApplication我的测试setUp方法之前就这样做了!我甚至没有注意到这一段时间,因为它似乎发生在测试套件启动期间甚至没有达到Eclipse断点的地方,但写入日志onCreate显示它实际上被调用.

这完全超出了我的范围.当Android的测试运行器实例化并执行实际应用程序时,为什么我要使用模拟应用程序对象?考虑到instrumentation runner在其自己的线程中运行,并且在执行此操作时生成主应用程序线程,这甚至更成问题.这意味着正在执行的测试和Application.onCreate被调用之间存在竞争条件.如果你在那里做任何可能影响测试的事情,例如写入共享偏好文件,那么你就完全搞砸了,因为你的测试会随机失败.

我是否遗漏了某些内容,或者这只是对测试框架的严重疏忽?

更新 这似乎ApplicationTestCase也会影响.在我的测试用例开始之前,我可以在我的应用程序类中找到一个断点onCreate.我们在那里启动了一个即发即弃的AsyncTask,它会随机失败,因为我没有机会嘲笑它(记住,之前setUp在我的测试用例中调用它).这是我在onCreate这个模糊的调用过程中看到的堆栈跟踪:

Thread [<1> main] (Suspended (breakpoint at line 86 in QypeRadar))  
QypeRadar.onCreate() line: 86   
InstrumentationTestRunner(Instrumentation).callApplicationOnCreate(Application) line: 969   
ActivityThread.handleBindApplication(ActivityThread$AppBindData) line: 4244 
ActivityThread.access$3000(ActivityThread, ActivityThread$AppBindData) line: 125    
ActivityThread$H.handleMessage(Message) line: 2071  
ActivityThread$H(Handler).dispatchMessage(Message) line: 99 
Looper.loop() line: 123 
ActivityThread.main(String[]) line: 4627    
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
Method.invoke(Object, Object...) line: 521  
ZygoteInit$MethodAndArgsCaller.run() line: 868  
ZygoteInit.main(String[]) line: 626 
NativeStart.main(String[]) line: not available [native method]  
Run Code Online (Sandbox Code Playgroud)

callApplicationOnCreate尽管文档清楚地说明了为什么测试运行器:

在测试调用createApplication()之前,测试用例不会调用onCreate().这使您有机会在onCreate()之前设置或调整任何其他框架或测试逻辑.

这是一个平淡的谎言 - 它没有给我机会!

Mac*_*rse 3

Roboguice也有同样的问题。在这里检查一下。

  • +1 对于有用的材料,我以前不知道`attachBaseContext`!但是,它没有帮助:测试运行程序仍然调用无参数构造函数,如果我删除它,我会得到一个异常:“InstantiationException -- newInstance failed: no &lt;init&gt;()”。如果我保留无参数构造函数,则无论我是否调用 setApplication,仍会在原始应用程序对象上调用 onCreate,因此问题仍然存在。 (3认同)