UI tests en Kotlin

Si os pasáis por la serie de codelabs de google Advanced Android in Kotlin veréis uno sobre Testing and Dependency Injection. No es sólo un ejercicio de test sino que es toda una guia de arquitectura para aplicaciones Android.

Cuando llegamos a la tercera sección empezamos a escribir tests de interfaces de usuario con Espresso. La primera vez que lo ejecutamos impresiona ver cómo nuestra app comienza a ejecutarse y a hacer cosas sola. Aunque está archivado como un codelab avanzado, aún se puede exprimir un poco más introduciendo el patrón Page Object.

Patrón Page Object

El sentido del page object es esconder todo el código necesario para replicar los pasos que hay que hacer para navegar por la app, realizar acciones como un usuario etc… y ofrecer una interfaz limpia que nos permita escribir tests más semánticos y mantenibles.

Para verlo en acción, hemos usado el propio código de la solución final del codelab que podéis encontrar aquí:

https://github.com/googlecodelabs/android-testing/tree/end_codelab_3

Trabajaremos a partir de la rama “end_code_lab3”.

Page Object

Comenzamos añadiendo esta clase Page que hace gran parte de la magia. La añadimos al source set “androidTest”:

open class Page {
    companion object {
        inline fun <reified T : Page> on(): T {
            return Page().on()
        }
    }

    inline fun <reified T : Page> on(): T {
        val page = T::class.constructors.first().call()
        page.verify()
        //Thread.sleep(500) //To give time when asynchronous calls are invoked
        return page
    }

    open fun verify(): Page {
        // Each subpage should have its default assurances here
        return this
    }

    fun back(): Page {
        Espresso.pressBack()
        return this
    }
}

Si queréis profundizar más en esto, pasaros por Page Object Pattern in Kotlin for UI Test Automation On Android de Kate Savelova.

Al final, esta clase se usa para poder definir una API fluida que nos permitirá organizar el código que necesitamos para navegar, realizar acciones, comprobar cosas en las páginas, vistas, etc. Prestad especial atención a la función verify. Esta función se usa para comprobar si la página que queremos se ha cargado.

Vamos a añadir nuestro primer test. Vamos al archivo AppNavigationTest.kt y añadamos un nuestro test que añadirá una nueva tarea a la app:

@Test
fun createNewTask()  {
    // Start up Tasks screen
    val activityScenario = ActivityScenario.launch(TasksActivity::class.java)
    dataBindingIdlingResource.monitorActivity(activityScenario)
   
    // When using ActivityScenario.launch, always call close()
    activityScenario.close()
}

Este es el código inicial para el test que simplemente lanza la TaskActivity. Para entenderlo mejor, leed el code lab https://developer.android.com/codelabs/advanced-android-kotlin-training-testing-survey#0. Quiero centrarme en explicar cómo aplicar el patrón Page Object y no explicar todo lo que enseña el code lab ^_^

El código completo de nuestro test es:

@Test
fun createNewTask()  {
    // Start up Tasks screen
    val activityScenario = ActivityScenario.launch(TasksActivity::class.java)
    dataBindingIdlingResource.monitorActivity(activityScenario)

    val testTask= Task("title", "description")

    Page.on<TasksPage>()
        .tapOnAddButton()
        .on<AddTaskPage>()
        .addTask(testTask)
        .on<TasksPage>()
        .checkAddedTask(testTask)

    // When using ActivityScenario.launch, always call close()
    activityScenario.close()
}

La “belleza” del test es que nos dice lo que hace de manera muy semántica:

  1. Crea una task
  2. En la página TasksPage, hace tap en el boton Add
  3. En la página AddTaskPage, añade la task que creamos en el paso 1
  4. Ahora en la página TaskPage, comprueba que se ha añadido la task.

Es muy semántico, y simple. Pero aún no compila, no te preocupes. Vamos a arreglarlo:

Añadimos la dependencia de gradle en el build.gradle de la app:

  • implementation “org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion”

Clases TasksPage y AddTaskPage

Vamos a añadir las clases TasksPage y AddTaskPage en el mismo paquete donde está nuestro PageObject:

class TasksPage : Page() {
    override fun verify(): TasksPage {
        onView(withId(R.id.tasks_container_layout))
            .check(matches(isDisplayed()))
        return this
    }

    fun tapOnAddButton(): TasksPage {
        onView(withId(R.id.add_task_fab)).perform(ViewActions.click())
        return this
    }


    fun tapOnEditTask(): TasksPage {
        onView(withId(R.id.edit_task_fab)).perform(ViewActions.click())
        return this
    }

    fun checkAddedTask(testTask: Task): TasksPage {
        onView(withText(testTask.title))
        return this
    }
}

class AddTaskPage: Page() {
    override fun verify(): AddTaskPage {
        Espresso.onView(withId(R.id.add_task_title_edit_text))
            .check(ViewAssertions.matches(isDisplayed()))
        return this
    }

    fun addTask(task: Task):AddTaskPage{
        onView(withId(R.id.add_task_title_edit_text))
            .perform(clearText(), typeText(task.title))
        onView(withId(R.id.add_task_description_edit_text))
            .perform(clearText(), typeText(task.description))
        onView(withId(R.id.save_task_fab)).perform(click())
        return this
    }
}

En estas clases está todo el código de Espresso que necesitamos para hacer las interacciones, pero bien ordenadito y recogidito. Si no lo hiciéramos así, terminaríamos con un test muy largo, con todos esos métodos de Espersso en un solo test, con lo que tendríamos un test difícil de leer y mantener. Además, si hiciésemos más tests de este tipo, tendríamos bastante código repetido entre los tests.

Si ejecutamos el test, el resultado será similar a:

Running test

Veamos el test equivalente sin usar el patrón PageObject:

@Test
fun createNewTaskWithoutPageObject(){
    val activityScenario = ActivityScenario.launch(TasksActivity::class.java)
    dataBindingIdlingResource.monitorActivity(activityScenario)

    val task= Task("title", "description")

    //check tasks page open
    onView(withId(R.id.tasks_container_layout))
        .check(matches(isDisplayed()))

    //tap on add button
    onView(withId(R.id.add_task_fab)).perform(ViewActions.click()) 

    //check task page is open
    onView(withId(R.id.add_task_title_edit_text))
        .check(ViewAssertions.matches(isDisplayed()))

    //add task
    onView(withId(R.id.add_task_title_edit_text))
        .perform(ViewActions.clearText(), ViewActions.typeText(task.title))
    onView(withId(R.id.add_task_description_edit_text))
        .perform(ViewActions.clearText(), ViewActions.typeText(task.description))
    onView(withId(R.id.save_task_fab)).perform(click())

    //check task page is open
    onView(withId(R.id.tasks_container_layout))
        .check(matches(isDisplayed()))

    //check added task
    onView(withText(task.title))

    // When using ActivityScenario.launch, always call close()
    activityScenario.close()
}

¿Qué test preferirías mantener?

Los beneficios de usar este patrón para crear test de interfaz de usuario son:

  • Test semánticos: Como podemos ver, el código es muy descriptivo, está escrito como si fuera una novela.
  • Mantenimiento:
    • Cada vez que cambie la interfaz, sólo cambiaremos aquellas páginas que se han visto afectados. Pero con esta arquitectura, es fácil encontrarlos, y es más fácil averiguar porqué ha fallado.
    • Añadir nuevos test es más rápido ya que no tendremos que estar duplicando código.

Resumen

El patrón Page Object está muy extendido a la hora de hacer tests de UI en otras plataformas como Java, JavaScript, C#. Una vez que se entiende, como me pasa a mí, algo hace clic en la cabeza. Y es muy fácil de aplicar.

Si quereis verlo en directo, podeis pasaros por el fork que dejo disponible en: https://github.com/juanlao/android-testing/tree/end_codelab_3

Espero que os sirva de algo estas líneas.

Referencias

https://www.elmosoft.net/pageobject-pattern-in-kotlin-for-ui-test-automation-on-android/

https://developer.android.com/codelabs/advanced-android-kotlin-training-testing-survey

TFS, Xamarin y MSTests

Hace un tiempo vimos un pequeño truco para poder ejecutar tests en las builds de TFS para proyectos Windows Phone.

Me ha sido necesario hacer lo mismo con proyectos con Xamarin Android y Xamarin iOS y aquí os pongo mi experiencia y cómo lo he resuelto. Continue reading “TFS, Xamarin y MSTests”

[Evento CartujaDotNet] Wave Engine

Wave EngineImagina que quieres hacer un juego, pero sólo quieres programarlo una vez y desplegarlo en la mayoría de plataformas posibles.

Deja de soñar y aprende a usar Wave Engine y podrás desplegar tus juegos en iOS, Android, Windows 8 y Windows Phone.

Los grandes Marcos Ligthyear y David Woody nos enseñarán todo lo necesario (y quizás algo más … ) para empezar a sacarle partido a Wave.

¿Dónde y cuando?

En el Cloud Pointing de Sevilla.

c Biología, 12, Edificio Vilamar 2, 3ª Planta
Parque Empresarial Nuevo Torneo
41015 Sevilla

El Jueves 23 de Mayo de 19:30 a 21:30.

Aquí tenéis juegos reales hechos con Wave Engine. Y estas son  unas cuantas demos tecnológicas.

¿Te lo vas a perder? Pues regístrate aquí

Difoosion

Me llena de orgullo y satisfacción que me hayan acogido en Difoosion como editor en su blog sobre noticias de Windows Phone: Winphone metro.

Logo de Winphone Metro

Tienen una red de blogs bastante interesante sobre el mundo móvil, no sólo de Windows Phone:

Logo Andro4all

Andro4All: Noticias sobre la plataforma Android.

Logo Applesencia

Applesencia: Noticias sobre Apple.

Logo Xombit

Xombit: Noticias sobre ciencia, tecnología, cultura, gadgets, series y juegos.

Logo XombitGamesXombit Games: Noticias sobre videojuegos de todas las plataformas

Uyuyuy, una sorpresa de última hora y es que ayer se lanzó:

Logo SportAdictosUn blog sobre deporte, salud y nutrición.

La verdad es que es una red de blogs muy recomendable para estar al tanto de lo que se cuece sobre estos temas y es que se actualizan bastante a menudo y creo que a los que me leéis os puede interesar.

Espero que os gusten.

Más tiempo para Cell·APP Awards

Las plegarias han sido oídas y  hemos ampliado el plazo para presentar juegos y aplicaciones a Cell·APP Awards:

Cell·App Awards

Desarrolla tu app usando CELL·SDK. Debes rellenar este formulario para participar y enviarnos el formulario de suscripción.

  • Fin de Inscripción: 31/05/2012
  • Último día para enviarnos tu app: 15/06/2012
  • Periodo de votaciones Online: Empezará una vez envíes tu app y nosotros la subamos. Este periodo acabará el 26 de Junio
  • El Jurado valorará las apps más votadas a partir del 28 de Junio.
  • La entrega de premios será el 29 de Junio.

Todavía no tienes Cell·SDK?! O_o

Pues descárgalo aquí.

Cell·SDK y el emulador de Android

Hace unas semanas se publicó una actualización del emulador de Android que muchos estábamos esperando.

Entre otras cosas, la característica fundamental, y una de las más esperadas, es que esta versión del emulador por fin soporta la aceleración de GPU, necesaria para ejecutar aplicaciones que necesitan OPEN GL 2.0. Continue reading “Cell·SDK y el emulador de Android”

Push Notifications en Cell·SDK

La semana pasada publicamos Cell·SDK 1.2 con un montón de nuevas características y algunas correcciones que hacen del desarrollo multiplataforma en iOS, Android y Windows Phone aún más sencillo.

En el post de hoy vamos a ver cómo enlazar lo que tenemos en el tutorial de Push notifications para Windows Phone y lo que podemos encontrar en la web de Microsoft sobre cómo mandar notificaciones a nuestros dispositivos.

Con el mismo código fuente que tenemos disponible en Github para la aplicación de ejemplo en el  dispositivo nos va a valer para este ejemplo.

Tenemos que tener en cuenta que debemos programarnos una pequeña aplicación/servicio para poder enviar notificaciones al servicio de notificaciones de Microsoft. Tal y como vemos en el diagrama y documentación de Microsoft:

Arquitectura Push

Nosotros tenemos que implementarnos el “Cloud Service” así que vamos a ver un ejemplo de cómo hacerlo según se indica aquí. De este último enlace sólo nos interesa la parte de “Sending a Toast Notification

Vamos a crear un proyecto de ASP.NET vacío y vamos a incluir cuatro controles TextBox y un botón para enviar la notifiación:

Página de envío

Ahora vamos a darle código al evento clic del botón:

protected void SendToast_Click(object sender, EventArgs e)
 {
 try
 {
 // Get the URI that the Microsoft Push Notification Service returns to the push client when creating a notification channel.
 // Normally, a web service would listen for URIs coming from the web client and maintain a list of URIs to send
 // notifications out to.
 string subscriptionUri = TextBoxUri.Text.ToString();

HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);

// Create an HTTPWebRequest that posts the toast notification to the Microsoft Push Notification Service.
 // HTTP POST is the only method allowed to send the notification.
 sendNotificationRequest.Method = "POST";

// The optional custom header X-MessageID uniquely identifies a notification message.
 // If it is present, the same value is returned in the notification response. It must be a string that contains a UUID.
 // sendNotificationRequest.Headers.Add("X-MessageID", "");

// Create the toast message.
 string toastMessage = "<?xml version="1.0" encoding="utf-8"?>" +
 "" +
 "" +
 "" + TextBoxTitle.Text.ToString() + "" +
 "" + TextBoxSubTitle.Text.ToString() + "" +

" " +
 "";

// Set the notification payload to send.
 byte[] notificationMessage = Encoding.Default.GetBytes(toastMessage);

// Set the web request content length.
 sendNotificationRequest.ContentLength = notificationMessage.Length;
 sendNotificationRequest.ContentType = "text/xml";
 sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
 sendNotificationRequest.Headers.Add("X-NotificationClass", "2");

using (Stream requestStream = sendNotificationRequest.GetRequestStream())
 {
 requestStream.Write(notificationMessage, 0, notificationMessage.Length);
 }

// Send the notification and get the response.
 HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
 string notificationStatus = response.Headers["X-NotificationStatus"];
 string notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
 string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];

// Display the response from the Microsoft Push Notification Service.
 // Normally, error handling code would be here. In the real world, because data connections are not always available,
 // notifications may need to be throttled back if the device cannot be reached.
 TextBoxResponse.Text = notificationStatus + " | " + deviceConnectionStatus + " | " + notificationChannelStatus;
 }
 catch (Exception ex)
 {
 TextBoxResponse.Text = "Exception caught sending update: " + ex.ToString();
 }

Este código puede estar tanto en una aplicación web, una aplicación de Windows forms, un servicio de Azure, etc…

Tan sólo tenéis que montarlo, desplegar la aplicación de ejemplo de github en el dispositivo ó en el emulador y copiar el Channel ID que saldrá en la ventana de Output de Visual Studio:

Channell ID en Visual Studio

Este código lo introducimos en la página web que hemos creado en el textbox primero y recibiremos en el dispositivo o emulador una notifiación Toast:

Toast Notification

Hay tres tipos de notificaciones para Windows Phone que podemos enviar:

  • Toast: Con documentación y ejemplos aquí
  • Tile: Con documentación y ejemplos aquí.
  • Raw: Con documentación y ejemplos aquí.

Os recomiendo que probéis a enviar otro tipo de notificaciones, en este ejemplo hemos usado el ejemplo de envío de notificaciones Toast.

Para ver el código fuente de la aplicación y cómo es la API Unificada para Android, iOS y Windows Phone de Cell·SDK no tenéis más que pasaros por aquí

Espero que os sirva.

Juan María Laó Ramos.

Lanzamos Cell·SDK1.1

Hace unos días publicamos la nueva versión de Cell·SDK. Podéis descargarlo totalmente gratis y probarlo aquí.

En esta versión hemos incluido un montón de nuevas características que nos facilitan aún más la vida y podéis verlas aquí. Entre otras características nuevas tenemos:

–          Status API: Esta API unifica la forma de acceder a la información de todos los dispositivos Android, iOS y Windows Phone, como por ejemplo al estado de la batería, el ID del dispositivo, la plataforma y un largo etcétera. Podéis descargar Cell·SDK ahora y aprender cómo usarlo en el tutorial de la Status API aquí.

–          Acceso a la cámara: Ahora podemos jugar de manera unificada en todas las plataformas con el nuevo sensor de cámara de una manera sencilla. Leed el tutorial, es muy sencillo.

–          Sistemas de análisis: Hemos incluido una API preparada para integrar diferentes sistemas de analítica para poder ver cómo los usuarios usan las aplicaciones. A día de hoy tenemos disponible la opción que ofrece Localytics pero pronto habrá más. Aquí podéis aprender a usarlo.

Aún hay más características nuevas pero en el post de hoy vamos a ver en detalle las nuevas funcionalidades añadidas con el ScreenManager.

Y es que a la hora de hacer un juego o aplicación es muy importante ofrecer una forma atractiva de crear los diferentes menús que vamos a mostrar. Con la experiencia y el feedback que nos habéis aportado hemos decidido incluir este ScreenManager que muchos os lo habréis implementado varias veces. Pues ahora ya no tenéis que implementarlo ya que lo ofrecemos de fábrica.

El uso es bien sencillo, para verlo en acción descargaos el ejemplo que tenemos en GitHub llamado ScreenManager aquí.

Vamos  a ver el código:

En la clase StaticContent tenemos una nueva variable estática llamada ScreenManager. Esta variable es la que nos va a permitir pasar de una pantalla (o Screen) a otra en nuestro juego o aplicación. Consiste en una colección de las diferentes pantallas que vamos a tener disponibles y que debemos ir añadiendo para poder ir de una pantalla a otra.

Cuando creamos un proyecto nuevo con la plantilla de Cell·SDK se crea la primera pantalla MainScreen.cs y se añade a esta colección por defecto en el archivo Application.cs

///
&lt;summary&gt; /// The main method for loading controls and resources.
/// &lt;/summary&gt;
public override void Initialize()
{
    base.Initialize();

<pre><code>StaticContent.Graphics.IsFullScreen = true;
StaticContent.Graphics.ApplyChanges();

StaticContent.ScreenManager.GoToScreen(new MainScreen());
</code></pre>

}

Vamos a ver cómo se usa directamente en la clase MainScreen del ejemplo. En la clase MainScreen.cs hemos definido unas cuantas variables del tipo Image que nos permitirán cargar los diferentes recursos del ejemplo para usarlo luego  como fondo de pantalla y como imágenes de los botones que tendremos en nuestra aplicación.

Pantalla de Inicio

Pero lo que realmente nos interesa es el uso de la variables StaticContent.ScreenManager así que veamos los eventos de release de los diferentes botones. Empezemos por el botón de opciones:

///
<summary> /// Go to options screen.
/// </summary>
///
private void bOptions_Released(Component source)
{
    StaticContent.ScreenManager.PushScreen(new OptionsScreen(), StaticContent.TransitionFactory.FadeBlackTransition);
}

Estamos añadiendo al ScreenManager una nueva pantalla, en este caso la de opciones, y con una transición FadeBlackTransition.Hay un montón de transiciones y añadiremos más en un futuro.

Ahora, en la pantalla de opciones (OptionsScreen.cs):

Pantalla de Opciones

Para seguir el flujo de navegación que estamos haciendo hemos añadido un botón para volver al a pantalla de inicio y en el evento Pressed hemos hecho un PopScreen, para eliminar la pantalla de la colección:

public override void BackButtonPressed()
{
    StaticContent.ScreenManager.PopScreen(StaticContent.TransitionFactory.FadeBlackTransition);
}

¡También con una transición!

Resumen

Hemos visto cómo podemos añadir diferentes pantallas a nuestra aplicación de una manera muy sencilla. Con este ScreenManager ya no tenemos que implementarnos nosotros mismos este tipo de mecanismos. Además tenemos un conjunto de transiciones por defecto bastante interesante que cubre la mayoría de efectos que podemos añadir a la hora de pasar de una pantalla a otra.

Os animo a que os descarguéis el código y probéis las diferentes transiciones que vienen por defecto y si tenéis alguna sugerencia sobre alguna transición que creéis podría aportar valor a las que ya vienen por defecto no dudéis en abrir un hilo en el foro sobre ello y lo estudiaremos.

Espero que sirva.

Juan María Laó Ramos (sígueme en twitter @juanlao)

Cell·APP Awards

No debe ser nuevo para vosotros Cell·SDK, un nuevo framework para crear aplicaciones multiplataforma en el que hemos trabajado durante mucho tiempo y que hace poco os presentamos.

Hoy lanzamos un concurso para animaros a todos a probarlo y conseguir fantásticos premios. Presentamos

Cell·APP Awards

Cell·APP Awards

Tan sólo tenéis que descargarlo  y empezar a programar la aplicación o juego que tengáis en mente, pero tened en cuenta una cosa, cuando lo hagáis, será totalmente multiplataforma, es decir, programaréis el juego no sólo para una de las plataformas más extendidas, sino que lo tendréis listo para desplegar en iOS, Android y Windows Phone. Algo que no muchos pueden decir.

Una vez que los descarguéis sólo tendréis que “aprender” a usarlo. Y lo pongo entre comillas porque es realmente fácil, gracias a la potencia que ofrece C# y a los fantásticos tutoriales y ejemplos que tenemos disponibles es realmente fácil.

El concurso comienza el 1 de Marzo y tenéis toda la información disponible aquí.

Si todavía te lo estás pensando, presta atención a los premios:

 1º Premio: Licencia CellSDK Starter + Ipad2 + Nokia Lumia 800 + $250 Publicidad Inmobi + Promoción en MarketPlace (Microsoft)

2º Premio: Licencia Starter CellSDK + Nokia Lumia 800 + $150 Publicidad Inmobi

3º Premio: Licencia Starter CellSDK+ Nokia Lumia 800 + $100 Publicidad Inmobi

4º Premio: Licencia CellSDK Basic + $75 Publicidad Inmobi

5º Premio: Licencia CellSDK Basic + $75 Publicidad Inmobi

¿De verdad que te lo estás pensando todavía?

Resumiendo, increíbles premios, tutoriales, ejemplos y un foro donde poder preguntar dudas sobre el desarrollo de Cell·SDK.

Espero veros por los foros y … que gane el mejor ;-).

P/D: Sígueme en twitter @juanlao.

 

Design a site like this with WordPress.com
Get started