Download - Testeas o k ase??

Transcript
Page 1: Testeas o k ase??

@Guardiola31337 - pguardiola.com

Pablo GuardiolaTesteas o k ase??

Page 2: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaAgenda

‣ Importancia del testing sobre dispositivos móviles

‣ Robolectric

‣ Demo

Page 3: Testeas o k ase??

‣ Número de apps Android en el market: 866033‣ Porcentaje de apps de baja calidad: 23 %

@Guardiola31337 - pguardiola.comPablo GuardiolaNumerosas apps en los markets = Competencia brutal

Page 4: Testeas o k ase??

‣ Porcentaje de apps con menos de 3 ratings: 43.9 %‣ Porcentaje de apps entre 0 y 4 estrellas: 65.22 %

@Guardiola31337 - pguardiola.comPablo GuardiolaNumerosas apps en los markets = Competencia brutal

Page 5: Testeas o k ase??

‣ No cabrees a tus usuarios

@Guardiola31337 - pguardiola.comPablo Guardiola¿El código hace exactamente lo que quieres?

Page 6: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo Guardiola¿El código hace exactamente lo que quieres?

Page 7: Testeas o k ase??

‣ Testing manual = mucho tiempo

@Guardiola31337 -pguardiola.comPablo Guardiola¿Podemos reducir el tiempo dedicado a testing usando tests automáticos?

Page 8: Testeas o k ase??

‣ Testing automático

@Guardiola31337 - pguardiola.comPablo Guardiola¿Podemos reducir el tiempo dedicado a testing usando tests automáticos?

Page 9: Testeas o k ase??

‣ ¡Cuidado con las actualizaciones!

@Guardiola31337 -pguardiola.comPablo GuardiolaVivimos en un mundo ágil

Page 10: Testeas o k ase??

@Guardiola31337 -pguardiola.comPablo GuardiolaTesteas o k ase??

Page 11: Testeas o k ase??

‣ Incrementa el nivel de confianza que se tiene del código

‣ Hacer testing “obliga” a escribir código modular

‣ Se desarrolla un producto de calidad

@Guardiola31337 - pguardiola.comPablo GuardiolaVentajas de hacer testing

Page 12: Testeas o k ase??

‣ Go, go, go!

@Guardiola31337 - pguardiola.comPablo GuardiolaAndroid testing

Page 13: Testeas o k ase??

‣ JUnit

@Guardiola31337 - pguardiola.comPablo GuardiolaAndroid testing

‣ Los métodos de android.jar devuelven Stub!

Page 14: Testeas o k ase??

‣ Android testing framework

@Guardiola31337 - pguardiola.comPablo GuardiolaOtras opciones

‣ Tests deben ejecutarse en un terminal o emulador

Page 15: Testeas o k ase??

‣ Separar código Java y Android

‣ POJO’s

‣ Tests instrumentales

‣ Mocking framework

‣ ¡¡¡NO HACER!!!

@Guardiola31337 - pguardiola.comPablo GuardiolaOtras opciones

Page 16: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaOtras opciones

‣ Entonces, ¿qué?

Page 17: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo Guardiola¿Por qué usar Robolectric?

‣ Es rápido

‣ Interacción con las clases de Android

‣ Incluye HTTP/API testing

‣ Permite invocar métodos privados

‣ Muy fácil de integrar con otros frameworks

Page 18: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaAdemás, Robolectric te permite...

‣ Usar JUnit 4

‣ Iteraciones rápidas

‣ Permite aplicar TDD en el desarrollo

‣ Verificar la lógica y el comportamiento frente a la implementación

Page 19: Testeas o k ase??

‣ Shadows

@Guardiola31337 - pguardiola.comPablo Guardiola¿Cómo funciona?

Page 20: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo Guardiola¿Cómo funciona?

Page 21: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo Guardiola¿Cómo funciona?

Page 22: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo Guardiola¿Cómo funciona?

‣Robolectric actúa como un proxy

Page 23: Testeas o k ase??

‣ Se debe indicar con una anotación qué clase es la encargada de realizar el test

@Guardiola31337 - pguardiola.comPablo GuardiolaShow me the code!

@RunWith(RobolectricTestRunner.class) // <== REQUIRED for Robolectric!public class HomeActivityTest { @Test public void shouldHaveAButtonThatSaysPressMe() throws Exception { // test code here }}

Page 24: Testeas o k ase??

‣ En ocasiones Robolectric está oculto...

@Guardiola31337 - pguardiola.comPablo GuardiolaShow me the code!

@RunWith(RobolectricTestRunner.class)public class HomeActivityTest { @Test public void shouldHaveHappySmiles() throws Exception { String appName = new MyActivity() .getResources().getString(R.string.app_name); assertThat(appName, equalTo("SampleRobolectric")); }}

‣ ¡Escondido! Pero haciendo su trabajo \o/

Page 25: Testeas o k ase??

‣ Métodos para acceder al estado de los objetos Android

@Guardiola31337 - pguardiola.comPablo GuardiolaShadows

<ImageView android:id="@+id/pivotal_logo" android:layout_width="fill_parent" android:layout_height="wrap_content" android:src="@drawable/pivotallabs_logo" android:layout_marginBottom="10dip" > @Testpublic void shouldHaveALogo() throws Exception { ImageView pivotalLogo = (ImageView)activity.findViewById(R.id.pivotal_logo); ShadowImageView shadowPivotalLogo = Robolectric.shadowOf(pivotalLogo); assertThat(shadowPivotalLogo.resourceId, equalTo(R.drawable.pivotallabs_logo));}

‣Acceso a estado y variables, de otro modo sería imposible

Page 26: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaHTTP testing

@RunWith(RobolectricTestRunner.class)public class HttpTest { @Test public void testGet_FormsCorrectRequest_noBasicAuth() throws Exception { Robolectric.addPendingHttpResponse(200, "OK"); new Http().get("www.codemotion.es",            Maps.<String, String>newHashMap(),            null,            null); assertThat(((HttpUriRequest) Robolectric.getSentHttpRequest(0)).getURI(),            equalTo(URI.create("www.codemotion.es"))); }}

Page 27: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaHTTP testing

‣ Robolectric hace de mock server, necesita saber cómo responder a la llamada para evitar RuntimeException

‣ Respuesta por defecto compartida

Robolectric.addPendingHttpResponse(200, "OK");

@RunWith(RobolectricTestRunner.class)public class HttpTest { @Before public void setup() { Robolectric.addPendingHttpResponse(200, "OK"); } ...}

Page 28: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaHTTP testing

‣ Otros ejemplos

@Test public void shouldReturnCorrectResponse() throws Exception { Robolectric .addPendingHttpResponse(666, "it's all cool"); Http.Response response = http.get("www.example.com", new HashMap<String, String>(), null, null);    assertThat(fromStream(response.getResponseBody()), equalTo("it's all cool"));    assertThat(response.getStatusCode(), equalTo(666)); }}

‣ Métodos correctos, cabeceras...

Page 29: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaExtendiendo Robolectric

‣ Robolectric no tiene funcionalidad para todo‣ Robolectric permite extender las clases Shadow

@[email protected]()__constructo__@RealObject

Page 30: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaInconvenientes

‣ No hay clases Shadow para todo‣ No todo se comporta del mismo modo que en la DVM‣ Android no es Java

Page 31: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo Guardiola¿Por qué no usar directamente el código Android?

‣ Difícil conseguir los .jar reales‣ Difícil trabajar con código nativo‣ Difícil dejar de usar las clases Shadow

Page 32: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0

2.0

Page 33: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0

‣ Uso del SDK de Android

‣ No más excepciones Stub!

‣ Objetivo eliminar el 99% de las clases Shadow

Page 34: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0

‣ El paquete de soporte no usa clases Shadow

‣ Fragments, action bar, loaders usan su implementación real

‣ Tests tendrán mismo comportamiento que en los dispositivos

Page 35: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0

‣ Se pueden testear estilos y temas

‣ Acceso a los recursos del sistema

‣ Soporte ActionBarSherlock

‣ Mejoras de rendimiento y corrección de bugs

Page 36: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0

‣ Testing bajo diferentes configuraciones del dispositivo

@Test @Config("en")public void shouldGiveEnglishResponses() throws Exception { assertThat(activity.findViewById(R.id.message)) .hasText("Hello!"); }}

@Test @Config("fr")public void shouldGiveFrenchResponses throws Exception { assertThat(activity.findViewById(R.id.message)) .hasText("Bonjour!"); }}

Page 37: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0

‣ ActivityController mayor control sobre el ciclo de vida

FooActivity foo = Robolectric.buildActivity(FooActivity.class)        .create().start().resume().get();

ActivityController<FooActivity> fooController = Robolectric.buildActivity(FooActivity.class).create();FooActivity foo = fooController.get();// Ensure the user was injected.assertThat(foo.user).isNotNull();// Log the user out.foo.user.expireSession();fooController.start().resume();// Ensure the activity is now finishing.assertThat(foo).isFinishing();

Page 38: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0

‣ El uso del SDK de Android está aumentando considerablemente

‣ Todo el mundo puede contribuir:

‣ https://github.com/robolectric/robolectric‣ http://robolectric.org/‣ http://robolectric.blogspot.com.es/

Page 39: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaDemo

Project name: SampleRobolectricPackage name: com.pguardiola.samplerobolectric

Activity name: MyActivityAdd Framework Support -> Maven

Page 40: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaDemo

<groupId>com.pguardiola.samplerobolectric</groupId> <artifactId>SampleRobolectric</artifactId> <version>1.0-SNAPSHOT</version> <packaging>apk</packaging> <name>My Sample App</name>

<dependencies> <dependency> <groupId>com.google.android</groupId> <artifactId>android</artifactId> <version>4.1.1.4</version> <scope>provided</scope> </dependency>

<!-- Make sure this is below the android dependencies --> <dependency> <groupId>org.robolectric</groupId> <artifactId>robolectric</artifactId> <version>2.1.1</version> <scope>test</scope> </dependency>

Page 41: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaDemo

<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies>

<build> <finalName>${project.artifactId}</finalName>

<plugins> <plugin> <groupId>com.jayway.maven.plugins.android.generation2</groupId> <artifactId>android-maven-plugin</artifactId> <version>3.6.1</version> <configuration> <sdk> <!-- platform or api level (api level 16 = platform 4.1)--> <platform>18</platform> </sdk> <undeployBeforeDeploy>true</undeployBeforeDeploy> </configuration> <extensions>true</extensions> </plugin> </plugins> </build>

Page 42: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaDemo

‣ Alt+Enter -> Create Test -> JUnit4

@RunWith(RobolectricTestRunner.class)public class MyActivityTest { @Test public void shouldHaveHappySmiles() throws Exception { String appName = new MyActivity().getResources() .getString(R.string.app_name); assertThat(appName, equalTo("SampleRobolectric")); }}

Page 43: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaDemo

‣ Imports

import org.junit.Test;import org.junit.runner.RunWith;import org.robolectric.RobolectricTestRunner;import static org.hamcrest.CoreMatchers.equalTo;

import static org.junit.Assert.assertThat;

Page 44: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaDemo

Run -> MyActivityTest

MyActivityTest fails

SampleRobolectric pass

Page 45: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo Guardiola¿Preguntas?

Page 46: Testeas o k ase??

@Guardiola31337 - pguardiola.comPablo GuardiolaGracias

Happy testing!!Pablo Guardiola

@Guardiola31337