java.lang.IllegalStateException: there must have been some overlap for resourceIdToResName! expected 5815 but got 5814 at org.robolectric.res.MergedResourceIndex.merge(MergedResourceIndex.java:25) at org.robolectric.res.MergedResourceIndex.(MergedResourceIndex.java:17) at org.robolectric.res.RoutingResourceLoader.(RoutingResourceLoader.java:22) at org.robolectric.RobolectricTestRunner.createAppResourceLoader(RobolectricTestRunner.java:598) at org.robolectric.RobolectricTestRunner.getAppResourceLoader(RobolectricTestRunner.java:582) at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:98) at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:401) at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:219) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:174) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
在我花了很久時間debug與search之後,發現在xml內的小差異會造成test fail android:id="@android:id 以及 android:id="@+id
只有android要求必須使用@android:id的才使用這種設定方式 例如 tabhost,ListFragment
否則一律使用 android:id="@+id ,錯用這個設定會造成Robolectric 無法 test
在projct成功可以test之後我遇到了另一個問題,由於我們的project implement了
ActionBarSherlock 所以在測試的時候常常會看到一些關於actionbar設定的nullpointer
為了解決這個問題,就必須在測試前預先做一些相關的設定
ActionBarSherlockRobolectric 提供了相關的解法,由於他提供的解法是給舊版本的,所以在這邊我們必須做一些小修改,只需要將
shadowOf(mActivity).setContentView(contentView);
修改成
mActivity.getWindow().setContentView(contentView);
就完成了
接著我就可以開始做相關的測試 例如我希望測試從mainactivity 導向某個fragment之後的測試
我可以這樣寫
@Before public void init(){ ActionBarSherlock.registerImplementation(ActionBarSherlockRobolectric.class); ActionBarSherlock.unregisterImplementation(ActionBarSherlockNative.class); ActionBarSherlock.unregisterImplementation(ActionBarSherlockCompat.class); } @Test @Config(reportSdk = 10, manifest = "AndroidManifest.xml") public void shouldNotBeNull() throws Exception { ShadowApplication shadowApplication = Robolectric.shadowOf(Robolectric.application); shadowApplication.declareActionUnbindable("com.google.android.gms.analytics.service.START"); Fragment myFragment = new myTestFragment(); startFragment( myFragment ); assertNotNull( myFragment ); } public static void startFragment( Fragment fragment ) { SherlockFragmentActivity activity = Robolectric.buildActivity( MainActivity.class ) .create() .start() .resume() .get(); FragmentManager fragmentManager = activity.getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.add( fragment, null ); fragmentTransaction.commit(); }
需要注意的是,我在init做了相關的設定之後,接著在test的地方做了一些相關的Config,
AndroidManifest是要測試project的AndroidManifest.xml 否則會出現resourceNameNotFound
由於我們的project有使用google trace analytics所以必須加入下面這行
shadowApplication.declareActionUnbindable("com.google.android.gms.analytics.service.START");
否則會出現
java.lang.NullPointerException at com.google.analytics.tracking.android.AnalyticsGmsCoreClient$AnalyticsServiceConnection.onServiceConnected(AnalyticsGmsCoreClient.java:176) at org.robolectric.shadows.ShadowApplication$2.run(ShadowApplication.java:246) at org.robolectric.util.Scheduler$PostedRunnable.run(Scheduler.java:162) at org.robolectric.util.Scheduler.runOneTask(Scheduler.java:107) at org.robolectric.util.Scheduler.advanceTo(Scheduler.java:92) at org.robolectric.util.Scheduler.advanceToLastPostedRunnable(Scheduler.java:68) at org.robolectric.util.Scheduler.unPause(Scheduler.java:25) at org.robolectric.shadows.ShadowLooper.unPause(ShadowLooper.java:220) at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:259) at org.robolectric.util.ActivityController.create(ActivityController.java:111) at org.robolectric.util.ActivityController.create(ActivityController.java:123) at MyFragmentTest.startFragment(MyFragmentTest.java:61) at MyFragmentTest.shouldNotBeNull(MyFragmentTest.java:50) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:233) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:174) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
接著myTestFragment 其實是使用mock的原理,由於我測試的Fragment在init的時候會去
onCreateOptionsMenu ,並且執行 mItem.getActionView(), 並且做一些相關的設定
但是我們的actionbar是用mock出來的所以在getActionView的時候會回傳null,
由於Menu的相關功能我可以額外寫一個測試,所以在這裡我並不想測試這部分也不想關心這部分,所以我直接mock了我想測試的fragment並且override了onCreateOptionsMenu的method,範例如下
public class myTestFragment extends MyFragment{ @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // TODO Auto-generated method stub //super.onCreateOptionsMenu(menu, inflater); } }
在相關的設定都設定完成之後,我run了一次test結果卻依舊是紅燈
android.view.InflateException: <merge /> can be used only with a valid ViewGroup root and attachToRoot=true at android.view.LayoutInflater.inflate(LayoutInflater.java:455) at android.view.LayoutInflater.inflate(LayoutInflater.java:396) at android.view.LayoutInflater.inflate(LayoutInflater.java:352) at ActionBarSherlockRobolectric.setContentView(ActionBarSherlockRobolectric.java:40) at com.actionbarsherlock.app.SherlockFragmentActivity.setContentView(SherlockFragmentActivity.java:261) at com.nineyi.MainActivity.onCreate(MainActivity.java:268) at android.app.Activity.performCreate(Activity.java:5104) at org.fest.reflect.method.Invoker.invoke(Invoker.java:112) at org.robolectric.util.ActivityController$1.run(ActivityController.java:116) at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:257) at org.robolectric.util.ActivityController.create(ActivityController.java:111) at org.robolectric.util.ActivityController.create(ActivityController.java:123) at MyFragmentTest.startFragment(MyFragmentTest.java:61) at MyFragmentTest.shouldNotBeNull(MyFragmentTest.java:50) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:233) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:174) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)這個地方我目前還想不到解法,原因是在MainActivity使用了<merge> 當作我們的root,造成了他的錯誤,由於目前還找不到特別的解法,所以目前這部分我也只能先將source改成 releativeLayout,希望之後有其他的方法可以解決這個問題
在經過了一番
不過這只不過是個開始,測試的路才剛開通而已~
相關參考文件
https://gist.github.com/JakeWharton/3803294
https://github.com/playhaven/playhaven-robolectric
http://robolectric.blogspot.mx/2013/05/configuring-robolectric-20.html
http://robolectric.blogspot.tw/2013/04/the-test-lifecycle-in-20.html
http://stackoverflow.com/questions/17993239/getsupportactionbar-returns-null-with-robolectric/18034473#18034473
沒有留言:
張貼留言