Robolectric 2.1.1で単体テストを実行しようとしていますが、カスタムレイアウト(ViewPagerIndicatorクラスなど)を拡張できません。これが私のレイアウトだとします:
_<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<TextView
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:text="test"
Android:id="@+id/test_test"/>
<com.viewpagerindicator.CirclePageIndicator
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"/>
</LinearLayout>
_
これを私のテストクラスと考えてください。
_@RunWith(RobolectricTestRunner.class)
public class TestRoboActivityTest {
private TestRoboActivity mActivity;
@Before
public void setUp() throws Exception {
mActivity = Robolectric.buildActivity(TestRoboActivity.class).create().get();
}
@After
public void tearDown() throws Exception {
mActivity = null;
}
@Test
public void testSanity() throws Exception {
Assert.assertNotNull(mActivity);
}
}
_
「mvn clean test」を実行すると、
テストのエラー: testSanity(TestRoboActivityTest):XMLファイル。\ res\layout\test.xml行#-1(申し訳ありませんが、まだ実装されていません):クラスcom.viewpagerindicator.CirclePageIndicatorの膨張エラー
かっこいいので、カスタムビューはまだサポートされていないようです。 website でサンプルのRobolectricプロジェクトをチェックすると、1つの解決策はLayoutInflaterからレイアウトを膨張させることです。
_@RunWith(RobolectricTestRunner.class)
public class TestRoboActivityTest {
private View mTestRoboActivityView;
@Before
public void setUp() throws Exception {
mTestRoboActivityView = LayoutInflater.from(new Activity()).inflate(R.layout.test, null);
}
@After
public void tearDown() throws Exception {
mTestRoboActivityView = null;
}
@Test
public void testSanity() throws Exception {
Assert.assertNotNull(mTestRoboActivityView);
}
}
_
その結果:
テストエラー: testSanity(TestRoboActivityTest):XMLファイル。\ res\layout\test.xml行#-1(申し訳ありませんが、まだ実装されていません):クラスin.viewpagerindicator.CirclePageIndicatorの膨張エラー
私の最後の手段は、シャドウクラスを使用しようとしていました。
_@Implements(CirclePageIndicator.class)
public class CirclePageIndicatorShadow implements PageIndicator {
@Override
@Implementation
public void setViewPager(ViewPager view) {
// Stub
}
// etc.
}
_
@Config(shadows = {CirclePageIndicatorShadow.class})
を使用します。これは再び
テストエラー: testSanity(TestRoboActivityTest):XMLファイル。\ res\layout\test.xml行#-1(申し訳ありませんが、まだ実装されていません):クラスin.viewpagerindicator.CirclePageIndicatorの膨張エラー
編集(2014年12月)
次のstracktraceは、後でDavid Rabinowitzによって追加されたことに注意してください。関連している間、それは私が当時直面していた問題ではありません。
スタックトレースは次のとおりです。
_Android.view.InflateException: XML file .\res\layout\activity_home.xml line #-1 (sorry, not yet implemented): Error inflating class com.test.custom.RobotoTextView
at Android.view.LayoutInflater.createView(LayoutInflater.Java:613)
at Android.view.LayoutInflater.createViewFromTag(LayoutInflater.Java:687)
at Android.view.LayoutInflater.rInflate(LayoutInflater.Java:746)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java:489)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java:396)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java:352)
at org.robolectric.tester.Android.view.RoboWindow.setContentView(RoboWindow.Java:82)
at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.Java:273)
at Android.app.Activity.setContentView(Activity.Java)
at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.Java:12)
at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.Java:28)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.Java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.Java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.Java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.Java:27)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.Java:31)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.Java:241)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.Java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.Java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.Java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.Java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.Java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.Java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.Java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.Java:184)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.Java:177)
at org.junit.runners.ParentRunner.run(ParentRunner.Java:236)
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)
Caused by: Java.lang.reflect.InvocationTargetException
at Sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at Sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.Java:57)
at Sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.Java:45)
at Java.lang.reflect.Constructor.newInstance(Constructor.Java:525)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createView(LayoutInflater.Java:587)
at Android.view.LayoutInflater.createView(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createViewFromTag(LayoutInflater.Java:687)
at Android.view.LayoutInflater.createViewFromTag(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_rInflate(LayoutInflater.Java:746)
at Android.view.LayoutInflater.rInflate(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.Java:489)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.Java:396)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.Java:352)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java)
at org.robolectric.tester.Android.view.RoboWindow.setContentView(RoboWindow.Java:82)
at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.Java:273)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:601)
at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.Java:455)
at Android.app.Activity.setContentView(Activity.Java)
at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.Java:12)
at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.Java:28)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:601)
... 22 more
Caused by: Java.lang.RuntimeException: error converting RobotoMedium.ttf using EnumConverter
at org.robolectric.shadows.Converter.convertAndFill(Converter.Java:150)
at org.robolectric.shadows.Converter.convertAndFill(Converter.Java:50)
at org.robolectric.shadows.ShadowResources.createTypedArray(ShadowResources.Java:228)
at org.robolectric.shadows.ShadowResources.attrsToTypedArray(ShadowResources.Java:203)
at org.robolectric.shadows.ShadowResources.access$000(ShadowResources.Java:51)
at org.robolectric.shadows.ShadowResources$ShadowTheme.obtainStyledAttributes(ShadowResources.Java:460)
at Android.content.res.Resources$Theme.obtainStyledAttributes(Resources.Java)
at Android.widget.TextView.__constructor__(TextView.Java:561)
at Android.widget.TextView.<init>(TextView.Java:447)
at Android.widget.TextView.<init>(TextView.Java:442)
at com.test.custom.RobotoTextView.<init>(RobotoTextView.Java:16)
at Android.view.LayoutInflater.createView(LayoutInflater.Java:587)
at Android.view.LayoutInflater.createViewFromTag(LayoutInflater.Java:687)
at Android.view.LayoutInflater.rInflate(LayoutInflater.Java:746)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java:489)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java:396)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java:352)
at org.robolectric.tester.Android.view.RoboWindow.setContentView(RoboWindow.Java:82)
at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.Java:273)
at Android.app.Activity.setContentView(Activity.Java)
at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.Java:12)
at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.Java:28)
... 22 more
Caused by: Java.lang.RuntimeException: no value found for RobotoMedium.ttf
at org.robolectric.shadows.Converter$EnumOrFlagConverter.findValueFor(Converter.Java:375)
at org.robolectric.shadows.Converter$EnumConverter.fillTypedValue(Converter.Java:343)
at org.robolectric.shadows.Converter$EnumConverter.fillTypedValue(Converter.Java:336)
at org.robolectric.shadows.Converter.convertAndFill(Converter.Java:148)
at org.robolectric.shadows.Converter.convertAndFill(Converter.Java:50)
at org.robolectric.shadows.ShadowResources.createTypedArray(ShadowResources.Java:228)
at org.robolectric.shadows.ShadowResources.attrsToTypedArray(ShadowResources.Java:203)
at org.robolectric.shadows.ShadowResources.access$000(ShadowResources.Java:51)
at org.robolectric.shadows.ShadowResources$ShadowTheme.obtainStyledAttributes(ShadowResources.Java:460)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:601)
at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.Java:455)
at Android.content.res.Resources$Theme.obtainStyledAttributes(Resources.Java)
at Android.widget.TextView.$$robo$$TextView_347d___constructor__(TextView.Java:561)
at Android.widget.TextView.<init>(TextView.Java:447)
at Android.widget.TextView.<init>(TextView.Java:442)
at com.test.custom.RobotoTextView.<init>(RobotoTextView.Java:16)
at Sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at Sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.Java:57)
at Sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.Java:45)
at Java.lang.reflect.Constructor.newInstance(Constructor.Java:525)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createView(LayoutInflater.Java:587)
at Android.view.LayoutInflater.createView(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_createViewFromTag(LayoutInflater.Java:687)
at Android.view.LayoutInflater.createViewFromTag(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_rInflate(LayoutInflater.Java:746)
at Android.view.LayoutInflater.rInflate(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.Java:489)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.Java:396)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java)
at Android.view.LayoutInflater.$$robo$$LayoutInflater_1d1f_inflate(LayoutInflater.Java:352)
at Android.view.LayoutInflater.inflate(LayoutInflater.Java)
at org.robolectric.tester.Android.view.RoboWindow.setContentView(RoboWindow.Java:82)
at org.robolectric.shadows.ShadowActivity.setContentView(ShadowActivity.Java:273)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:601)
at org.robolectric.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.Java:455)
at Android.app.Activity.setContentView(Activity.Java)
at com.example.testrobocustomfont.MainActivity.onCreate(MainActivity.Java:12)
at com.example.testrobocustomfont.MainActivityTest.setUp(MainActivityTest.Java:28)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:601)
... 22 more
_
正しい方向を教えていただけますか?私はアイデアがありません。ありがとう。
ビューを使用するアクティビティを使用して、同じテストクラスでビューをテストします。この場合、Robolectricにそのアクティビティのインスタンスを提供するように指示し、それから膨らんだビューのインスタンスを取得します。
@Before
public void setup(){
activity = Robolectric.buildActivity(MyActivity.class).create().get();
View view = LayoutInflater.from(activity).inflate(R.layout.myView, null);
}
@Test
public void allElementsInViewProduct(){
assertNotNull(view.findViewById(R.id.view1));
assertNotNull(view.findViewById(R.id.view2));
assertNotNull(view.findViewById(R.id.view3));
}
LE:私はRobolectric 3.0を使用しているので、これがあなたに当てはまるかどうかわかりません。
この問題は、gradleがプロジェクトの依存関係(例:compile project(':lib-custom')
)と外部の依存関係(例:compile 'lib.package:name:1.1.0'
)を異なる方法でマージするために発生します。依存関係がマージされた後、アプリにはすべてのリソースフィールド(色、ID、ドロウアブルなど)を含むR.Java
ファイルがあります。ただし、生成されたR.Java
ファイルは、サブモジュールと外部依存関係をマージした後は異なって見えます。
この問題は、サブモジュールにカスタムビューがあるプロジェクトにのみ存在します。外部依存関係の場合、別の問題がありますが、これは簡単に修正できます。依存関係の種類について読む here .
プロジェクトの依存関係の結果R.Java
ファイルにはすべてのリソース識別子が含まれていますが、サブモジュールの識別子は元の整数識別子とは異なります:
com.lib.custom.R.color.primary != com.main.project.R.color.primary
R.Java
ファイルをマージした外部依存関係の場合、すべての外部依存関係からのR.Javaファイルのマージ結果のみ
com.lib.custom.R.color.primary == com.main.project.R.color.primary
私は2つの可能な解決策を見つけました:
例:
// add this dependency to your gradle file instead of project dependency
compile 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar'
// add library dependencies for robolectric (now robolectric knows
// about additional libraries to load resources)
Android.library.reference.1=../../../app/build/intermediates/exploded-aar/fr.avianey.com.viewpagerindicator/library/2.4.1
このソリューションの差分を確認できます here
Error inflating class
の問題も修正します。私は最初の解決策を好みますが、プロジェクトの依存関係を外部に変更することはできません。
また、この問題についてRobolectricチームに報告します。
追伸 githubのプロジェクト この問題に関連しています。
mTestRoboActivityView = LayoutInflater.from(new Activity()).inflate(R.layout.test, null);
このコード行で使用した「new Activity()」は、現在のアクティビティではなく、新しいアクティビティのインスタンスを意味します。現在のアクティビティにインスタンスを渡すことで、この問題を解決できます。このように使用します
public class TestRoboActivityTest {
private View mTestRoboActivityView;
private Context mContext;
public TestRoboActivityTest(Context mContext){
this.mContext=mContext;
}
@Before
public void setUp() throws Exception {
mTestRoboActivityView = (LayoutInflater.from(mContext)).inflate(R.layout.test, null);
}
@After
public void tearDown() throws Exception {
mTestRoboActivityView = null;
}
@Test
public void testSanity() throws Exception {
Assert.assertNotNull(mTestRoboActivityView);
}}
上記のコードが正常に機能するかどうかはわかりませんが、現在のアクティビティのインスタンスを参照するために使用します。それがあなたを助けるかもしれないことを参照してください。
Roboelectricでは、完全なAndroidフレームワークを使用せず、代わりにすべてのAndroid APIをモックアウトするため、Roboelectricでビューを膨らませることはできません。
実際のビュー表示動作をテストするためにロボエレクトリックを使用しないでください。単体テストに使用し、ビジネスロジックをテストするだけで、図面や表示などを表示することはできません。それを実現するには、プログラムでビューオブジェクトを作成し、Androidシステム(MockitoまたはPowermockのようなものを使用します。例えば、roboelecticでの簡単なビューテストの場合:
MyCustomView view = new MyCustomView();
assertNotNull(view.setSomeNo(2);
assertTrue(2, view.getSomeNo());
また、ビューの外観やレンダリングなどのレンダリングをテストする場合は、実際のデバイスで実行されるEspressoまたはRobotiumなどの機能テストフレームワークを使用する必要があります。