viernes, 29 de noviembre de 2013

Como utilizar Robolectric y JUnit en AndroidStudio


El otro día en el trabajo, vi la necesidad de comenzar un proyecto Android, y tenía que ver cómo incorporar la librería Robolectric y JUnit para realizar los test del proyecto. Y como utilizo de IDE el Android Studio, vi que todavía no hay muchos tutoriales sobre este tema en español, así que me pareció bueno dejarlo plasmado en un post.  




Para poder utilizar esto, vamos a recibir la ayuda de Jake Wharton (responsable también de la librería ActionBarSherlock ) y a utilizar su plugin para Gradle, eso lo pueden encontrar acá :D
https://github.com/JakeWharton/gradle-android-test-plugin





Lo queden hacer entonces, será crear un proyecto Android con el Android Studio y modificar el archivo build.gradle para que les quede de una forma similar a esta:


buildscript {
    repositories {
        mavenCentral()
        maven {
            url 'https://oss.sonatype.org/content/repositories/snapshots/'
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.6.+'
        classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.1-SNAPSHOT'

    }
}
apply plugin: 'android'
apply plugin: 'android-test'

repositories {
    mavenCentral()
    maven {
            url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
}

android {
    compileSdkVersion 18
    buildToolsVersion "18.0.1"

    defaultConfig {
            minSdkVersion 15
            targetSdkVersion 19
    }

    buildTypes {

        release {
                runProguard true
                    proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
            }
    }

    productFlavors {
            defaultFlavor {
                    proguardFile 'proguard-rules.txt'
            }
    }

    sourceSets {
            instrumentTest.setRoot('src/test')
    }
}

dependencies {

    testCompile 'junit:junit:4.10'
    testCompile 'org.robolectric:robolectric:2.1.+'
    testCompile 'com.squareup:fest-android:1.0.+'

    instrumentTestCompile 'junit:junit:4.10'
    instrumentTestCompile 'org.robolectric:robolectric:2.1.+'
    instrumentTestCompile 'com.squareup:fest-android:1.0.+'

}


Básicamente es agregar lo siguiente dentro de la sección buildscript:

maven {
            url 'https://oss.sonatype.org/content/repositories/snapshots/'

 
Y allí mismo en las dependencias:
classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.1-SNAPSHOT'

Después de eso agregamos el plugin con: apply plugin: 'android-test'

En la configuración de android, al final agregamos:

sourceSets {
            instrumentTest.setRoot('src/test')


 
Esto es para que Android Studio no busqué los test en la carpeta por defecto src/instrumentTest, y si lo haga en src/test

Y por último tenemos que agregar en nuestras dependencias las librerías que vamos a utilizar:

testCompile 'junit:junit:4.10'
testCompile 'org.robolectric:robolectric:2.1.+'
testCompile 'com.squareup:fest-android:1.0.+'

instrumentTestCompile 'junit:junit:4.10'
instrumentTestCompile 'org.robolectric:robolectric:2.1.+'
instrumentTestCompile 'com.squareup:fest-android:1.0.+'



Ya con eso, solo nos queda crear en la raíz de nuestro proyecto, dentro de la carpeta src, una llamada test, dentro de ella una java, para que quede de esta forma:




Casi por último sincronizamos el proyecto con gradle lo que nos va a descargar las librerías. Una vez que tengamos esto, para poder utilizar el framework Robolectric debemos agregar en cualquier parte de esa carpeta (test/java) una clase como esta:


import org.junit.runners.model.InitializationError;
import org.robolectric.AndroidManifest;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.res.Fs;

public class RobolectricGradleTestRunner extends RobolectricTestRunner {
    public RobolectricGradleTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    @Override protected AndroidManifest getAppManifest(Config config) {
        String manifestProperty = System.getProperty("android.manifest");
        if (config.manifest().equals(Config.DEFAULT) && manifestProperty != null) {
            String resProperty = System.getProperty("android.resources");
            String assetsProperty = System.getProperty("android.assets");
            return new AndroidManifest(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty),
                    Fs.fileFromPath(assetsProperty));
        }
        return super.getAppManifest(config);
    }
}


Ya con eso habremos terminado, ya podemos escribir nuestros test (siempre dentro del árbol de directorio bajo test/java ), este es un pequeño ejemplo de ello.

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertTrue;

@RunWith(RobolectricGradleTestRunner.class)
public class pruebaTest {

    @Test
    public void probandoTest(){
        assertTrue(true);
    }
}


Para correr los test solo necesitamos abrir la terminal dentro de la carpeta de nuestro proyecto y ejecutamos ./gradlew test (puede que la primera vez necesites darle permisos de ejecución al archivo con chmod +x gradlew) Si los test corren correctamente nos dira que BUILD SUCCESSFUL ;) en caso contrario (pueden probarlo colocando false en el anterior test) les mostrará el siguiente mensaje:
There were failing tests. See the report at:
Y una dirección de archivo, si lo colocan en un navegador web, podrán ver el informe de error y log de porque sucedió el mismo;)

Para trabajar y poder correr algunos test más interesante podrían hacer cosas como estas:


// Crear una activity
@Before
public void setup() {
    activity = Robolectric.buildActivity(MainActivity.class).get();
}

// comprobamos que no sean null las referencias que vamos a usar
@Test
public void noDebeSerNull() {
  assertThat(activity).isNotNull();

  TextView textView = (TextView) activity.findViewById(R.id.textView);
  assertThat(textView).isNotNull();

  Button button = (Button) activity.findViewById(R.id.button);
  assertThat(button).isNotNull();

  EditText editText = (EditText) activity.findViewById(R.id.editText);
  assertThat(editText).isNotNull();
}

// para luego poder comprobar cosas como esta
@Test
public void AccionAlPresionarBoton() {
  TextView textView = (TextView) activity.findViewById(R.id.textView);
  Button button = (Button) activity.findViewById(R.id.button);
  EditText editText = (EditText) activity.findViewById(R.id.editText);

  editText.setText("Hola");

  button.performClick();

  assertThat(textView).containsText("Hola, como estas?");
}


Espero que les sirva, creo que es una interesante forma de poder trabajar con el Android Studio, nos vemos en la próxima ;) 


P.D: Acá les dejo un ejemplo completo de un archivo de configuración gradle:
Gist: Archivo de configuración

Saludos a todos, Gabriel