如何防止ActivityUnitTestCase调用Application.onCreate?

我必须在这里错过一些东西。 ActivityUnitTestCase的JavaDoc表明这个testing用例对系统进行隔离testing:

这个类提供了单个活动的单独testing。 被testing的活动将在与系统基础结构最less连接的情况下创build,并且可以注入许多Activity的依赖关系的模拟版本或包装版本。

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

但是,任何ActivityUnitTestCase我开始启动(实际)应用程序并调用其onCreate方法。 更确切地说, InstrumentationTestRunner似乎正在这样做,甚至在我有机会在我的testingsetUp方法中设置应用程序之前setApplication ! 我甚至都没有注意到这一点,因为它似乎发生在testing套件启动的时候,甚至连Eclipse的断点都没有达到,但是写入onCreate的日志显示它实际上是被调用的。

这完全超出了我。 为什么我要在Android的testing运行器实例化并执行实际应用程序时使用模拟应用程序对象? 考虑到instrumentation runner运行在自己的线程中,这样会更成问题,并且在这样做时会产生主应用程序线程。 这意味着正在执行的testing和正在调用的Application.onCreate之间存在争用条件。 如果你在那里做任何可能影响你的testing的事情,例如写入一个共享的首选项文件,那么你完全搞砸了,因为你的testing会随机失败。

我是否错过了一些东西,或者这只是testing框架中的一个粗略的疏忽?

更新这似乎也影响ApplicationTestCase 。 在我的testing用例开始之前,我可以在应用程序类“ onCreate ”中获得一个断点。 我们在那里开始一个令人着迷的AsyncTask,它会随机失败,因为我没有机会嘲笑它(记住,这是在我的testing用例上调用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] 

为什么testing运行者callApplicationOnCreate即使文档清楚地说明:

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

这是一个平坦的谎言 – 这不给我机会!

Solutions Collecting From Web of "如何防止ActivityUnitTestCase调用Application.onCreate?"

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

我正在用匕首进行testing,所以可能这也是你的情况,因为你可能只想注入,不要调用Application.onCreate中的任何东西,所以这个对我来说很好(api17 +):

 private Context mContext; private Application mApplication; @Override protected void setUp() throws Exception { super.setUp(); mContext = new ContextWrapper(getInstrumentation().getTargetContext()) { @Override public Context getApplicationContext() { return mApplication; } }; mApplication = new MyAppMock(); mApplication.attachBaseContext(mContext); setApplication(app); } public void testActivityCreated() { Intent intent = AboutActivity.createIntent(mContext); setActivityContext(mContext); startActivity(intent, null, null); assertNotNull(getActivity()); } 

对于<api16,您需要使用reflection并调用Application.attach(context)而不是Application.attachBaseContext()来设置Application.mLoadedApk ,否则会崩溃。

我已经把所有东西放在一起,并制作了演示如何使用匕首进行testing的演示应用程序: https : //github.com/vovkab/dagger-unit-test

它还显示如何嘲笑你的应用程序,适用于任何Android版本。