Depuración y pruebas
Depuración en Xcode
Depuración “clásica” con NSLog y Asserts
La depuración clásica consiste en alterar el código fuente de forma temporal añadiendo una serie de directivas con el fin de mostrar mensajes informativos en la consola. Como ya hemos visto, la función habitual para enviar mensajes a la consola de XCode es
NSLog()
Antes de generar el binario de distribución para la App Store deberíamos eliminar todas las llamadas a
NSLog
que tengamos en el código para así dejar "limpia" la aplicación y evitar una posible relentización de la ejecución debido a la escritura en la consola.
Otro tipo de función con la cual podemos depurar nuestro código por consola es el llamado Assert. Los Asserts (o aserciones) son condiciones que se deben de cumplir para que continue la ejecución en un determinado momento. Estas deben de devolver
true
. En el caso de que algún assert no se cumpla se producirá una excepción en fase de ejecución que detendrá la aplicación en ese mismo instante almacenando todo el "log" en XCode para su posterior depuración.La directiva assert en Objective-C viene en forma de macro
assert()
a la cual se le pasa una condición que será que se tenga que evaluar a verdadero o falso. Si se evalúa a falso la aplicación se detendrá mostrando en la consola un log y si se evalúa a verdadero la aplicación continuará con su ejecución. Los asserts son usados frecuementes en APIs así como en códigos en fases de testeo.
assert
hace que el programa aborte inmediatamente cuando falla la aserciónDe modo alternativo podemos usar
NSAssert
, que a diferencia deasssert
:Cuando falla la aserción no aborta directamente sino que genera una excepción de tipo
NSInternalInconsistencyException
(que por supuesto también causará un crash si no la capturamos).Nos permite especificar un mensaje de error con argumentos
El depurador integrado de Xcode
El depurador visual integrado en Xcode es muy similar a los que hay en otros IDES. Podemos fijar breakpoints clicando en el margen izquierdo del código, y una vez parada la ejecución podemos ver el valor de las variables, continuar con la ejecución hasta el siguiente breakpoint, ir paso a paso, etc.
A diferencia de otros IDEs no hay un modo especial de ejecución para depurar el código, se parará en los breakpoints cuando ejecutamos la aplicación normalmente con
Product > Run
(o con el botón de “play” de la barra de herramientas). No obstante, en el “Breakpoint Navigator” podemos deshabilitar todos los breakpoints si queremos ignorarlos en un momento dado.
Una funcionalidad muy interesante es la de Quick Look, que nos permite ver el contenido de ciertas variables de forma “gráfica”. Por ejemplo si se trata de un UIImage
podemos ver una versión en pequeño de la imagen para comprobar rápidamente que corresponde con lo que esperamos
Como se ve en la figura anterior, cuando estamos depurando el código y la ejecución está parada en un punto, pasando el ratón por encima de una variable aparece un tooltip con información sobre ella. Pulsando sobre el pequeño icono en forma de “ojo” que aparece en el tooltip activamos el quick look. También podemos hacerlo pulsando el mismo icono en el “área de depuración” (parte inferior de la pantalla), donde aparecen las variables actuales
Quick look funciona con muchos tipos de variables: vistas (componentes de la interfaz de usuario, que como hemos visto aparecen “en pequeño”), localizaciones geográficas (aparece un mapa centrado en la localización), frames de vistas (aparece un rectángulo con las proporciones adecuadas y una anotación con el tamaño actual),curvas dibujadas con el API de gráficos, …
Testing
XCode tiene desde la versión 5 un framework de testing llamado
XCTest
(en las versiones anteriores se usaba otro distinto, denominadoOCUnit
).Desde Xcode 5, cuando creamos un proyecto se crea automáticamente un conjunto de pruebas unitarias vacío y un target para ejecutar esas pruebas con el mismo nombre del proyecto pero acabado en
"Test"
. Si tenemos un proyecto ya creado sin pruebas unitarias, podemos crearlas conFile > New > Target > Cocoa touch unit test
.En
XCTest
hay varios tipos distintos de pruebas unitarias:Tests de “lógica”: las clásicas pruebas en las que comprobamos si determinado método funciona o no correctamente.
Tests de “lógica” en modo asíncrono:
Tests de tiempo de respuesta: en los que podemos ver estadísticas del tiempo que tarda en ejecutarse determinado bloque de código. Podemos fijar un baseline de tiempo de modo que el test se considerará que no pasa si está por encima del baseline
El navegador de Tests
Escribir y ejecutar pruebas unitarias
Como ya hemos dicho,
XCTest
es muy similar a otros frameworks de pruebas unitarias comoJUnit
, así que no es muy complicado de usar para alguien que ya haya usado los otros.Por ejemplo, supongamos que tenemos un juego de tres en raya con el siguiente interfaz (simplificado)
Vamos a comprobar varias cosas
Que cuando se inicializa el tablero todas las casillas están vacías
Que las casillas se pueden obtener/fijar correctamente a un valor dado
Que cuando se intenta obtener/fijar una casilla que no existe se produce una excepción
Estructura de una suite de pruebas
Iríamos a la plantilla de clase de pruebas que ha creado Xcode e introduciríamos el siguiente código
Hay varios puntos a destacar:
Por defecto la plantilla coloca el
@interface
y la@implementation
de la clase de la suite de tests en el mismo archivo.m
. Esto es adecuado en la mayoría de los casos, ya que no vamos a referenciar la suite desde otras clases y no necesitamos por tanto un@interface
separadoAl igual que en
JUnit
hay dos métodos:setup
yteardown
que se ejecutan al inicio y al final de cada test, respectivamente.Las pruebas unitarias se implementan en métodos que deben devolver
void
y cuyo nombre debe comenzar portest
.Comprobamos el correcto funcionamiento de la lógica con los métodos
XCTAssert
Aserciones
En todas las aserciones podemos poner como parámetro final un mensaje (Un NSString
) que aparecerá si falla el test
Tenemos varios tipos de aserciones, por ejemplo:
XCTAssertTrue
yXCTAssertFalse
comprueban que algo es cierto o falso, respectivamenteXCTAssertEqual
sirve para comprobar la igualdad de valores escalares. En el ejemplo lo hemos usado para comprobar el contenido de las casillas al ser este unenum
. Tenemos también el contrario,XCTAssertNotEqual
XCTAssertEqualObjects
es como el anterior, pero para comparar igualdad entre objetos. Internamente llama alisEqual
.XCTAssertThrows
comprueba que una llamada a un método genera una excepción. Opcionalmente, podemos comprobar que además la excepción es de una clase específica.
Ejecutar las pruebas y ver el resultado
En el Test navigator podemos pulsar el pequeño botón de “play” que aparece al pasar el ratón por encima de cada test, para ejecutarlo individualmente o bien el que aparece en la suite completa para ejecutar todas sus pruebas.
Se pondrá en marcha el simulador de iOS con la aplicación, ejecutará las pruebas y terminará. En el test navigator y en el código fuente de la suite aparecerá un icono al lado de cada test indicando si ha pasado o no. Si no ha pasado aparecerá además un mensaje en el fuente indicándolo. También podemos ver los mensajes de error en el Log Navigator.
Pruebas de tiempo de respuesta
Con Xcode 6 se introduce un nuevo tipo de tests: los de tiempo de respuesta. Podemos ver estadísticas sobre el tiempo que tarda en ejecutarse un determinado bloque de código. Esto lo hacemos con el método measureBlock
, que acepta el bloque a ejecutar como parámetro
Referencias
Last updated