testeas o k ase??
Post on 22-May-2015
717 Views
Preview:
DESCRIPTION
TRANSCRIPT
@Guardiola31337 - pguardiola.com
Pablo GuardiolaTesteas o k ase??
@Guardiola31337 - pguardiola.comPablo GuardiolaAgenda
‣ Importancia del testing sobre dispositivos móviles
‣ Robolectric
‣ Demo
‣ 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
‣ 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
‣ No cabrees a tus usuarios
@Guardiola31337 - pguardiola.comPablo Guardiola¿El código hace exactamente lo que quieres?
@Guardiola31337 - pguardiola.comPablo Guardiola¿El código hace exactamente lo que quieres?
‣ Testing manual = mucho tiempo
@Guardiola31337 -pguardiola.comPablo Guardiola¿Podemos reducir el tiempo dedicado a testing usando tests automáticos?
‣ Testing automático
@Guardiola31337 - pguardiola.comPablo Guardiola¿Podemos reducir el tiempo dedicado a testing usando tests automáticos?
‣ ¡Cuidado con las actualizaciones!
@Guardiola31337 -pguardiola.comPablo GuardiolaVivimos en un mundo ágil
@Guardiola31337 -pguardiola.comPablo GuardiolaTesteas 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
‣ Go, go, go!
@Guardiola31337 - pguardiola.comPablo GuardiolaAndroid testing
‣ JUnit
@Guardiola31337 - pguardiola.comPablo GuardiolaAndroid testing
‣ Los métodos de android.jar devuelven Stub!
‣ Android testing framework
@Guardiola31337 - pguardiola.comPablo GuardiolaOtras opciones
‣ Tests deben ejecutarse en un terminal o emulador
‣ Separar código Java y Android
‣ POJO’s
‣ Tests instrumentales
‣ Mocking framework
‣ ¡¡¡NO HACER!!!
@Guardiola31337 - pguardiola.comPablo GuardiolaOtras opciones
@Guardiola31337 - pguardiola.comPablo GuardiolaOtras opciones
‣ Entonces, ¿qué?
@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
@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
‣ Shadows
@Guardiola31337 - pguardiola.comPablo Guardiola¿Cómo funciona?
@Guardiola31337 - pguardiola.comPablo Guardiola¿Cómo funciona?
@Guardiola31337 - pguardiola.comPablo Guardiola¿Cómo funciona?
@Guardiola31337 - pguardiola.comPablo Guardiola¿Cómo funciona?
‣Robolectric actúa como un proxy
‣ 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 }}
‣ 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/
‣ 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
@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"))); }}
@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"); } ...}
@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...
@Guardiola31337 - pguardiola.comPablo GuardiolaExtendiendo Robolectric
‣ Robolectric no tiene funcionalidad para todo‣ Robolectric permite extender las clases Shadow
@Implements@ImplementationRobolectric.getDefaultShadowClasses()__constructo__@RealObject
@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
@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
@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0
2.0
@Guardiola31337 - pguardiola.comPablo GuardiolaRobolectric 2.0
‣ Uso del SDK de Android
‣ No más excepciones Stub!
‣ Objetivo eliminar el 99% de las clases Shadow
@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
@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
@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!"); }}
@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();
@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/
@Guardiola31337 - pguardiola.comPablo GuardiolaDemo
Project name: SampleRobolectricPackage name: com.pguardiola.samplerobolectric
Activity name: MyActivityAdd Framework Support -> Maven
@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>
@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>
@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")); }}
@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;
@Guardiola31337 - pguardiola.comPablo GuardiolaDemo
Run -> MyActivityTest
MyActivityTest fails
SampleRobolectric pass
@Guardiola31337 - pguardiola.comPablo Guardiola¿Preguntas?
@Guardiola31337 - pguardiola.comPablo GuardiolaGracias
Happy testing!!Pablo Guardiola
@Guardiola31337
top related