使用 Robolectric 与 Loader 一起测试 Activity
Use Robolectric to test Activity with Loader
我有一个带有 Spinner 的 Activity,它使用 Loader 从 ContentProvider 中获取数据(根据多个来源的建议以及我之前所做的):
protected void onCreate(Bundle savedInstanceState) {
// ...
account = (Spinner) findViewById(R.id.account);
account.setAdapter(
new SimpleCursorAdapter(
this,
android.R.layout.simple_spinner_item,
null,
new String[]{ Contract.Accounts.COL_NAME },
new int[]{ android.R.id.text1 },
0));
getLoaderManager().initLoader(LOADER_ID_ACCOUNT, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(this,
Contract.Accounts.CONTENT_URI,
null,
null,
null,
null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
((SimpleCursorAdapter)account.getAdapter()).swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
((SimpleCursorAdapter)account.getAdapter()).swapCursor(null);
}
到目前为止一切顺利,当我 运行 使用该应用程序时,它就像一个魅力,但我为此 Activity 进行的单元测试现在不会 运行。
@Test
public void testAllElementsExist() {
Activity activity = setupActivity(AddTransactionActivity.class);
assertTrue(activity.findViewById(R.id.category) != null);
assertTrue(activity.findViewById(R.id.created_on_date) != null);
assertTrue(activity.findViewById(R.id.created_on_time) != null);
assertTrue(activity.findViewById(R.id.account) != null);
assertTrue(activity.findViewById(R.id.description) != null);
}
连最基本的测试都失败了:
java.lang.NullPointerException
at android.widget.SimpleCursorAdapter.findColumns(SimpleCursorAdapter.java:328)
at android.widget.SimpleCursorAdapter.swapCursor(SimpleCursorAdapter.java:345)
at pt.lemonade.AddTransactionActivity.onLoadFinished(AddTransactionActivity.java:185)
at pt.lemonade.AddTransactionActivity.onLoadFinished(AddTransactionActivity.java:28)
at android.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:482)
at android.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:450)
at android.content.Loader.deliverResult(Loader.java:143)
at android.content.CursorLoader.deliverResult(CursorLoader.java:113)
at android.content.CursorLoader.deliverResult(CursorLoader.java:43)
at android.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:254)
at android.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:91)
at android.os.ShadowAsyncTaskBridge.onPostExecute(ShadowAsyncTaskBridge.java:22)
at org.robolectric.shadows.ShadowAsyncTask.run(ShadowAsyncTask.java:40)
at org.robolectric.util.Scheduler$PostedRunnable.run(Scheduler.java:182)
at org.robolectric.util.Scheduler.runOneTask(Scheduler.java:125)
at org.robolectric.util.Scheduler.advanceTo(Scheduler.java:110)
at org.robolectric.util.Scheduler.advanceToLastPostedRunnable(Scheduler.java:86)
at org.robolectric.util.Scheduler.unPause(Scheduler.java:26)
at org.robolectric.shadows.ShadowLooper.unPause(ShadowLooper.java:231)
at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:270)
at org.robolectric.util.ActivityController.visible(ActivityController.java:166)
at org.robolectric.util.ActivityController.setup(ActivityController.java:202)
at org.robolectric.Robolectric.setupActivity(Robolectric.java:1388)
at pt.lemonade.AddTransactionActivityTest.testAllElementsExist(AddTransactionActivityTest.java:65)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:236)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=14=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:158)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
这是 Robolectric 2.4 的已知问题吗?有没有一种解决方法不会转化为写一堆阴影 类?
交易工具: Android Studio 1.1.0 激活了单元测试实验功能,Gradle 插件 1.0.1,Robolectric 2.4
此外,一些旁白问题:我最近听说最好使用 RxJava Observables,因为它更容易测试。是否可以替代LoaderManager?如何像 LoaderManager 那样缓存结果?你能给我一个查询 ContentProvider 的工作示例和单元测试以便我评估吗?
如果有人遇到同样的问题: Robolectric 缺少 ShadowSimpleCursorAdapter#swapCursor
实施。我添加了该方法以及其他修改并创建了一个拉取请求。你可以在 master 分支中找到它。对于仍在使用 2.4 版的任何人,请查看:https://github.com/robolectric/robolectric/issues/1677
我有一个带有 Spinner 的 Activity,它使用 Loader 从 ContentProvider 中获取数据(根据多个来源的建议以及我之前所做的):
protected void onCreate(Bundle savedInstanceState) {
// ...
account = (Spinner) findViewById(R.id.account);
account.setAdapter(
new SimpleCursorAdapter(
this,
android.R.layout.simple_spinner_item,
null,
new String[]{ Contract.Accounts.COL_NAME },
new int[]{ android.R.id.text1 },
0));
getLoaderManager().initLoader(LOADER_ID_ACCOUNT, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(this,
Contract.Accounts.CONTENT_URI,
null,
null,
null,
null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
((SimpleCursorAdapter)account.getAdapter()).swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
((SimpleCursorAdapter)account.getAdapter()).swapCursor(null);
}
到目前为止一切顺利,当我 运行 使用该应用程序时,它就像一个魅力,但我为此 Activity 进行的单元测试现在不会 运行。
@Test
public void testAllElementsExist() {
Activity activity = setupActivity(AddTransactionActivity.class);
assertTrue(activity.findViewById(R.id.category) != null);
assertTrue(activity.findViewById(R.id.created_on_date) != null);
assertTrue(activity.findViewById(R.id.created_on_time) != null);
assertTrue(activity.findViewById(R.id.account) != null);
assertTrue(activity.findViewById(R.id.description) != null);
}
连最基本的测试都失败了:
java.lang.NullPointerException
at android.widget.SimpleCursorAdapter.findColumns(SimpleCursorAdapter.java:328)
at android.widget.SimpleCursorAdapter.swapCursor(SimpleCursorAdapter.java:345)
at pt.lemonade.AddTransactionActivity.onLoadFinished(AddTransactionActivity.java:185)
at pt.lemonade.AddTransactionActivity.onLoadFinished(AddTransactionActivity.java:28)
at android.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:482)
at android.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:450)
at android.content.Loader.deliverResult(Loader.java:143)
at android.content.CursorLoader.deliverResult(CursorLoader.java:113)
at android.content.CursorLoader.deliverResult(CursorLoader.java:43)
at android.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:254)
at android.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:91)
at android.os.ShadowAsyncTaskBridge.onPostExecute(ShadowAsyncTaskBridge.java:22)
at org.robolectric.shadows.ShadowAsyncTask.run(ShadowAsyncTask.java:40)
at org.robolectric.util.Scheduler$PostedRunnable.run(Scheduler.java:182)
at org.robolectric.util.Scheduler.runOneTask(Scheduler.java:125)
at org.robolectric.util.Scheduler.advanceTo(Scheduler.java:110)
at org.robolectric.util.Scheduler.advanceToLastPostedRunnable(Scheduler.java:86)
at org.robolectric.util.Scheduler.unPause(Scheduler.java:26)
at org.robolectric.shadows.ShadowLooper.unPause(ShadowLooper.java:231)
at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:270)
at org.robolectric.util.ActivityController.visible(ActivityController.java:166)
at org.robolectric.util.ActivityController.setup(ActivityController.java:202)
at org.robolectric.Robolectric.setupActivity(Robolectric.java:1388)
at pt.lemonade.AddTransactionActivityTest.testAllElementsExist(AddTransactionActivityTest.java:65)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:236)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=14=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner.evaluate(RobolectricTestRunner.java:158)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
这是 Robolectric 2.4 的已知问题吗?有没有一种解决方法不会转化为写一堆阴影 类?
交易工具: Android Studio 1.1.0 激活了单元测试实验功能,Gradle 插件 1.0.1,Robolectric 2.4
此外,一些旁白问题:我最近听说最好使用 RxJava Observables,因为它更容易测试。是否可以替代LoaderManager?如何像 LoaderManager 那样缓存结果?你能给我一个查询 ContentProvider 的工作示例和单元测试以便我评估吗?
如果有人遇到同样的问题: Robolectric 缺少 ShadowSimpleCursorAdapter#swapCursor
实施。我添加了该方法以及其他修改并创建了一个拉取请求。你可以在 master 分支中找到它。对于仍在使用 2.4 版的任何人,请查看:https://github.com/robolectric/robolectric/issues/1677