test studio example activity android robolectric

android - studio - robolectric github



Prueba de vistas personalizadas con Robolectric (5)

Problema:

Este problema ocurre porque gradle fusiona las dependencias del proyecto (por ejemplo: compile project('':lib-custom'') ) y las dependencias externas (por ejemplo: compile ''lib.package:name:1.1.0'' ) de manera diferente. Después de que se fusionaron las dependencias, la aplicación tiene R.java archivo R.java con todos los campos de recursos (colores, identificadores, elementos extraíbles, ...). Pero el archivo R.java generado se ve diferente después de fusionar submódulos y dependencias externas.

Este problema existe solo con proyectos, que tienen vistas personalizadas en submódulos . En el caso de dependencias externas, hay otros problemas que se pueden solucionar fácilmente. Lea sobre tipos de dependencias here .

Para las dependencias del proyecto, el archivo R.java contiene todos los identificadores de recursos, pero los identificadores del submódulo no son iguales a sus identificadores enteros originales:

com.lib.custom.R.color.primary != com.main.project.R.color.primary

Para las dependencias externas se fusionó el archivo R.java solo un resultado de fusión de los archivos R.java de todas las dependencias externas

com.lib.custom.R.color.primary == com.main.project.R.color.primary

Solución:

He encontrado dos soluciones posibles:

  1. Convierta sus dependencias de submódulo a externo siempre que sea posible. Por ejemplo, para el indicador de viepager tiene un elemento en el repositorio maven.org - fr.avianey.com.viewpagerindicator: library. Pero esto aún no es suficiente: debe agregar el elemento relacionado al archivo project.properties en su conjunto de origen principal. Más información here

Ejemplo:

// 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

Puede verificar la diferencia para esta solución here

  1. Mueva todas sus vistas personalizadas en su aplicación principal. No es un buen enfoque mover las vistas personalizadas a la aplicación solo debido a las pruebas unitarias, pero esto también solucionará el problema con la Error inflating class .

Prefiero la primera solución pero a veces no es posible cambiar la dependencia del proyecto a externa.

También voy a informar sobre este problema al equipo de Robolectric.

PD Tengo un proyecto en Github relacionado con este problema.

Estoy intentando ejecutar pruebas unitarias con Robolectric 2.1.1 y no puedo conseguir que infle los diseños personalizados (p. Ej., Clases de ViewPagerIndicator). Supongamos que este es mi diseño:

<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>

Considera esta mi clase de prueba:

@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); } }

Ejecutar resultados de ''mvn clean test'' en

Tests in error: testSanity(TestRoboActivityTest): XML file ./res/layout/test.xml line #-1 (sorry, not yet implemented): Error inflating class com.viewpagerindicator.CirclePageIndicator

Genial, parece que las vistas personalizadas aún no son compatibles. Al comprobar el proyecto Robolectric de muestra en su website , una solución podría ser inflar el diseño 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); } }

lo que resulta en:

Tests in error: testSanity(TestRoboActivityTest): XML file ./res/layout/test.xml line #-1 (sorry, not yet implemented): Error inflating class com.viewpagerindicator.CirclePageIndicator

Mi último recurso fue tratar de usar clases de sombra:

@Implements(CirclePageIndicator.class) public class CirclePageIndicatorShadow implements PageIndicator { @Override @Implementation public void setViewPager(ViewPager view) { // Stub } // etc. }

y usando @Config(shadows = {CirclePageIndicatorShadow.class}) . Esto nuevamente resultó en

Tests in error: testSanity(TestRoboActivityTest): XML file ./res/layout/test.xml line #-1 (sorry, not yet implemented): Error inflating class com.viewpagerindicator.CirclePageIndicator

Editar (diciembre de 2014)

Tenga en cuenta que la siguiente stracktrace fue añadida más tarde por David Rabinowitz. Mientras estoy relacionado, no es el problema que estaba enfrentando en ese momento.

Aquí está el rastro de la pila:

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

¿Podrían ustedes por favor señalarme en la dirección correcta? Estoy sin ideas. Gracias.


¿Dónde está Viewpager? . Se está recibiendo un error porque CirclePageIndicator quiere inflar la vista, pero no hay nada que inflar. indicator.setViewPager (pager);


No se pueden inflar las vistas en Roboelectric ya que no utiliza el marco completo de Android, sino que se burla de todas las API de Android.

No debe usar roboeléctrico para probar el comportamiento de visualización de la vista real. Se debe usar para pruebas unitarias y solo para probar la lógica de su negocio y no para ver el dibujo / visualización, etc. Para lograrlo, puede crear objetos de vista y burlarse de ciertas partes que necesitan el sistema Android (use algo como Mockito o Powermock ). . por ejemplo, de simple vista de prueba en roboelectic:

MyCustomView view = new MyCustomView(); assertNotNull(view.setSomeNo(2); assertTrue(2, view.getSomeNo());

Además, si desea probar la representación de cómo se ve o representa la vista, etc., debe usar marcos de prueba funcionales como Espresso o Robotium que se ejecutan en un dispositivo real.


Pruebo vistas en la misma clase de prueba con la actividad que las usa. En este caso le digo a Robolectric que me dé una instancia de esa Actividad y de eso obtengo una instancia de la vista inflada:

@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: Uso Robolectric 3.0, así que no estoy seguro de si esto se aplica a ti.


mTestRoboActivityView = LayoutInflater.from(new Activity()).inflate(R.layout.test, null);

En esta línea de código que utilizó ''nueva actividad ()'' significa instancia de nueva actividad, que no corresponde a su actividad actual. Puede resolver este problema pasando instancia en la Actividad actual. Usa así:

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); }}

No estoy seguro de que el código anterior funcione bien, pero utilícelo como referencia, instancia de la actividad actual. Remítalo puede ser de ayuda.