J'essaie d'exécuter des tests unitaires avec Robolectric 2.1.1 et je ne parviens pas à gonfler les dispositions personnalisées (par exemple, les classes ViewPagerIndicator). Supposons que ceci soit ma mise en page:
<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>
Considérez ceci comme ma classe de test:
@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);
}
}
L'exécution des résultats du "test propre mvn"
Tests en erreur: TestSanity (TestRoboActivityTest): fichier XML.\Res\layout\test.xml ligne # -1 (désolé, pas encore implémentée): Erreur lors de l’ajout de la classe com.viewpagerindicator.CirclePageIndicator
Cool, il semble donc que les vues personnalisées ne soient pas encore prises en charge. Vérification de l'exemple de projet Robolectric sur leur site Web , Une solution pourrait être de gonfler la présentation à partir de 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);
}
}
qui se traduit par:
Tests en erreur: TestSanity (TestRoboActivityTest): fichier XML.\Res\layout\test.xml ligne # -1 (désolé, pas encore implémentée): Erreur lors de l’ajout de la classe com.viewpagerindicator.CirclePageIndicator.
Mon dernier recours était d'essayer d'utiliser des classes d'ombre:
@Implements(CirclePageIndicator.class)
public class CirclePageIndicatorShadow implements PageIndicator {
@Override
@Implementation
public void setViewPager(ViewPager view) {
// Stub
}
// etc.
}
et en utilisant @Config(shadows = {CirclePageIndicatorShadow.class})
. Cela a encore abouti à
Tests en erreur: TestSanity (TestRoboActivityTest): fichier XML.\Res\layout\test.xml ligne # -1 (désolé, pas encore implémentée): Erreur lors de l’ajout de la classe com.viewpagerindicator.CirclePageIndicator.
Edit (Décembre 2014)
Veuillez noter que la chaîne de caractères suivante a été ajoutée plus tard par David Rabinowitz. Bien qu’ils soient liés, ce n’est pas le problème auquel j’étais confronté à l’époque.
Voici la trace de la pile:
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
Pourriez-vous me diriger dans la bonne direction? Je suis à court d'idées ... Merci.
Ce problème se produit car gradle fusionne les dépendances de projet (ex: compile project(':lib-custom')
) et les dépendances externes (ex: compile 'lib.package:name:1.1.0'
) de manière différente. Après la fusion des dépendances, l'application contient le fichier R.Java
avec tous les champs de ressources (couleurs, identifiants, éléments dessinables, ...). Mais le fichier R.Java
généré est différent après la fusion des sous-modules et des dépendances externes.
Ce problème existe uniquement avec les projets qui ont des vues personnalisées dans les sous-modules. En cas de dépendances externes, il existe un autre problème, qui peut être facilement résolu. Lisez à propos des types de dépendances ici .
Pour les dépendances du projet, le fichier résultat R.Java
contient tous les identifiants de ressources, mais les identifiants du sous-module ne correspondent pas à leurs identifiants entiers d'origine:
com.lib.custom.R.color.primary != com.main.project.R.color.primary
Pour les dépendances externes, le fichier R.Java
fusionné est simplement un résultat de la fusion des fichiers R.Java de toutes les dépendances externes
com.lib.custom.R.color.primary == com.main.project.R.color.primary
J'ai trouvé deux solutions possibles:
Exemple:
// 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
Vous pouvez vérifier diff pour cette solution ici
Error inflating class
.Je préfère la première solution, mais il est parfois impossible de changer la dépendance du projet en externe.
Je vais également rendre compte de ce problème à l'équipe de Robolectric.
P.S. J'ai projet sur github lié à cette question.
Je teste des vues dans la même classe de test avec l'activité qui les utilise. Dans ce cas, je dis à Robolectric de donner une instance de cette activité et à partir de là, je reçois une instance de la vue gonflée
@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: J'utilise Robolectric 3.0, donc je ne suis pas sûr que cela s'applique à vous.
Vous ne pouvez pas gonfler les vues dans Roboelectric car celui-ci n'utilise pas l'intégralité de la structure Android, mais simule toutes les API Android.
Roboelectric ne doit pas être utilisé pour tester le comportement réel de l'affichage des vues . Il doit être utilisé pour les tests unitaires et uniquement pour tester votre logique métier et non pour visualiser des dessins/affichages, etc. certaines parties nécessitant le système Android (utilisez quelque chose comme Mockito ou Powermock ) . par exemple, des tests de vue simples en mode roboélectique:
MyCustomView view = new MyCustomView();
assertNotNull(view.setSomeNo(2);
assertTrue(2, view.getSomeNo());
De même, si vous souhaitez tester le rendu de l'apparence ou du rendu de votre vue, vous devez utiliser des frameworks de tests fonctionnels tels que Espresso ou Robotium qui s'exécutent sur un périphérique réel.