Workshop iOS 3: Testing, protocolos y extensiones

49
5. Testing, protocols & extensions ÍNDICE 5. Testing, protocols & extensions ............................................................................... 1 Objetivos .................................................................................................................. 2 1. Requisitos ............................................................................................................. 2 2. Protocols ............................................................................................................... 2 2.1. ¿Qué son? .............................................................................................................. 2 2.2. Propósito ............................................................................................................... 2 3. Configurar Proyecto en Xcode .............................................................................. 3 3.1. Código ................................................................................................................... 6 3.2. Documentación de código ....................................................................................... 8 4. Tests unitarios .................................................................................................... 11 4.1. Código del test ..................................................................................................... 13 4.2. Ejecutar los tests desde Xcode .............................................................................. 14 4.3. Cobertura de código desde Xcode .......................................................................... 14 4.4. Ejecutar los tests desde línea de comando ............................................................. 17 4.3. Cobertura de código desde línea de comando ......................................................... 18 5. Integración continua .......................................................................................... 20 5.1. Configuración de Travis-CI .................................................................................... 21 5.2. Configuración de Coveralls con Travis-CI................................................................ 25 5.3. Publicación de informes en github-pages................................................................ 30 5.4. Configuración de Jenkins....................................................................................... 47 Material de interés ................................................................................................. 48

Transcript of Workshop iOS 3: Testing, protocolos y extensiones

5. Testing, protocols & extensions

ÍNDICE

5. Testing, protocols & extensions ............................................................................... 1

Objetivos .................................................................................................................. 2

1. Requisitos ............................................................................................................. 2

2. Protocols ............................................................................................................... 2

2.1. ¿Qué son? .............................................................................................................. 2

2.2. Propósito ............................................................................................................... 2

3. Configurar Proyecto en Xcode .............................................................................. 3

3.1. Código ................................................................................................................... 6

3.2. Documentación de código ....................................................................................... 8

4. Tests unitarios .................................................................................................... 11

4.1. Código del test ..................................................................................................... 13

4.2. Ejecutar los tests desde Xcode .............................................................................. 14

4.3. Cobertura de código desde Xcode .......................................................................... 14

4.4. Ejecutar los tests desde línea de comando ............................................................. 17

4.3. Cobertura de código desde línea de comando ......................................................... 18

5. Integración continua .......................................................................................... 20

5.1. Configuración de Travis-CI .................................................................................... 21

5.2. Configuración de Coveralls con Travis-CI ................................................................ 25

5.3. Publicación de informes en github-pages................................................................ 30

5.4. Configuración de Jenkins ....................................................................................... 47

Material de interés ................................................................................................. 48

Objetivos

Entender el funcionamiento de los protocolos

Aprender a crear tests unitarios

Generar informes de resultados de tests y de cobertura de código

Integración continua (Travis vs. Jenkins)

1. Requisitos

En este workshop se usarán las siguientes herramientas:

Github: deberéis tener cuenta propia para poder crearos un repositorio público en el que

configurar la integración continua

Travis CI: servicio de integración continua en el cloud

Coveralls: servicio para mostrar informes de cobertura de código en el cloud

Slather: librería para generar informes de cobertura

Jazzy: utilidad para generar documentación

xcpretty: utilidad para generar informes de tests

2. Protocols

2.1. ¿Qué son?

Los protocolos son una manera de definir una serie de métodos, constructores, etc. que debe

tener una clase o estructura, pero sin llegar a implementarlos.

Están relacionados con el concepto de herencia múltiple en otros lenguajes como C++, y son

similares al concepto de interface en otros lenguajes como C# o Java.

Se suelen utilizar para abstraer determinadas partes del código para que pueda ser extendida en

un futuro (como veremos en el ejemplo) y su uso es muy habitual para implementar delegates

(que veremos en siguientes workshops, aunque los delegates siguen una filosofía similar a los

listeners en Java).

Sintaxis:

<modifier> protocol ProtocolName : <Extended protocol> {

func someMethod()

func anotherMethodWithParameters(param1: Int, param2: Int)

}

2.2. Propósito

En este workshop implementaremos una función de medida de distancia de edición, o también

conocida como distancia de Levenstein https://es.wikipedia.org/wiki/Distancia_de_Levenshtein

La distancia de edición, es algo que se suele utilizar para comparar textos (palabras), cuando no

son exactamente iguales.

La distancia de edición indica la cantidad de caracteres que es necesario añadir, eliminar, mover

o reemplazar para que dos textos sean iguales.

Su uso es habitual en buscadores de texto (como Google), ya que cuando se realiza una búsqueda

es posible que el usuario cometa errores tipográficos o que el texto no coincida exactamente con

lo que hay indexado en la base de datos, pero sea muy similar. A grandes rasgos, uno de las

algoritmos que se usa en este tipo de herramientas es este (entre muchas otra más cosas que

no detallaremos aquí).

Aunque el uso habitual de la distancia de edición es para la comparación de Strings, en realidad

el algoritmo permite comparar colecciones de cosas (en este caso un string es una colección de

caracteres), por lo que en el workshop implementaremos el algoritmo mediante protocolos para

que así pueda ser utilizado para comparar más cosas a parte de strings de texto.

Finalmente extenderemos la clase String para que implemente el protocolo que hemos creado y

de este modo poderla utilizar con EditDistance utilizando la siguiente sintaxis: extension <Class> : <Protocol> {

func method() {

}

}

Donde <Class> es la clase que queremos extender, y en este caso (aunque no es obligatorio)

además implementamos un Protocolo. En la extensión de la clase añadimos el método method().

3. Configurar Proyecto en Xcode

A continuación se describen los pasos a seguir para configurar el proyecto en Xcode tal y como

está en el repositorio.

El resultado debería ser el mismo que lo que hay en la rama init del repositorio.

1. Abrir Xcode y seleccionar la opción para crear un proyecto nuevo. Escoger la opción de framework

de cocoa touch.

2. Asignar un nombre al proyecto, la cuenta de desarrollo y la ubicación donde se guardará el

proyecto

3. Guardar el proyecto

4. Al guardar el proyecto, Xcode nos genera una estructura inicial del proyecto con un test unitario

de ejemplo (el cual sustituiremos). A continuación se muestra el aspecto general del proyecto

tras su creación.

3.1. Código

A continuación se proporciona el código para implementar la distancia de edición:

3.2. Documentación de código

En el ejemplo de código puede verse que las clases, métodos y variables miembro pueden

documentarse siguiendo una nomenclatura especial.

Xcode detecta los bloques de código del tipo /** .. */ o que empiecen por tres barras /// y los

trata de forma especial considerándolos como comentarios de documentación.

La documentación se escribe en formato markdown, por lo que resulta sencillo escribir títulos con

la sintaxis #título#, negrita como **negrita**, *cursiva*, etc.

Además, como puede verse, la documentación admite ciertas palabras clave para documentar

parámetros y valores retornados.

Estos bloques de texto son tratados de forma especial por Xcode de modo que al hacer alt + click

sobre una variable, tipo o método, nos mostrará la documentación sobre éste en un popup.

Del mismo modo, también puede verse esta misma documentación en el Quick Help inspector en

el panel de la derecha.

También es posible generar documentación en formato web para tenerla como referencia y

colgarla en un servidor (igual que la documentación de Apple).

Para ello puede utilizarse una herramienta como Jazzy.

Para instalar Jazzy:

Para ejecutar Jazzy:

jazzy --clean --author Alberto Irurueta --github_url

https://github.com/albertoirurueta/swift-protocols-and-generics-workshop --

xcodebuild-arguments -

project,./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj,-

scheme,swiftProtocolsAndGenerics --module swiftProtocolsAndGenerics --output

docs

Nótese que se proporcionan argumentos de xcodebuild para especificar la ruta del archivo de

proyecto y el esquema a documentar. En los argumentos proporcionados, los espacios que

normalmente se proporcionarían en el comando de xcodebuild deben sustituirse por comas.

xcodebuild es una herramienta de línea de comando que permite realizar tareas como

compilación, ejecución de tests, archivado, generación de ipa's, etc desde línea de comando, por

lo que será de gran utilidad para automatizar tareas en el servidor de integración.

Una vez ejecutada esta línea de comando, tendremos en la carpeta docs una página web con

toda la documentación del proyecto.

4. Tests unitarios

A continuación se describen los pasos a seguir para crear tests unitarios

1. Pulsar con el botón derecho sobre el grupo de tests (carpeta amarilla de tests en el

project navigator).

2. Seleccionar nuevo archivo y escoger la opción de nuevo test unitario (no confundir con

la opción de tests de UI)

3. Asignar un nombre al archivo y un lenguaje de programación

4. Aseguraos de que el check del archivo de tests está asociado al target de tests y no al

del framework, ya que de lo contrario estaríais incluyendo el archivo en la librería.

4.1. Código del test

A continuación se proporcionan tests unitarios de la distancia de edición.

Nótese que al comparar con un array de strings, se escoje el string que más separece (el que

tiene menor distancia de edición).

4.2. Ejecutar los tests desde Xcode

Para ejecutar los tests, en el panel izquierdo de Xcode seleccionamos el Test navigator.

Desde el test navigator podremos seleccionar qué tests ejecutar.

Tras la ejecución de los tests se mostrarán unas marcas que indican si se ejecutaron

correctamente o no, tal y como se muestra a continuación.

4.3. Cobertura de código desde Xcode

La cobertura de código nos permite saber realmente qué partes del código se han ejercitado con

la ejecución de los tests y que partes aún no han sido testeadas.

A medida que un proyecto crece es importante ver de un vistazo qué áreas están testeadas y

cuáles faltan por testear.

Del mismo modo, a medida que un proyecto crece es interesante tener un servidor que ejecute

todos los tests por nosotros y nos ofrezca informes de cobertura y de tests de forma automatizada

para poder hacer un mejor seguimiento de la calidad del código de un proyecto, ya que

normalmente en el desarrollo normal el desarrollador no tendrá que ejecutar todos los tests en

su máquina, sólo aquellos que sean relevantes para la parte del código que esté desarrollando.

El resto de tests los ejecutará el servidor de integración

Por defecto Xcode deshabilita la cobertura de código, ya que al ejecutar los tests con la cobertura

de código habilitada hay una pequeña penalización de rendimiento (la cual no tiene importancia

a menos que realmente se esté midiendo el rendimiento con el profiler).

Para poder obtener informes de cobertura, tanto en local como en el servidor, es necesario

habilitar la cobertura de código en el esquema del proyecto. Para ello deben seguirse los

siguientes pasos:

1. En el selector de esquemas, editar el esquema

2. En la opción de test activar la opción de recolección de datos de cobertura (Gather coverage

data). Más adelante también veremos que activamos la opción "shared"

Una vez activada la recolección de datos de cobertura, si volvemos a ejecutar los tests, veremos

en el Report Navigator del panel de la izquierda un resumen de los tests que han pasado y los

que no, así como información de resumen de la cobertura de código. El informe de tests y de

cobertura es interactivo y nos permite ir a las líneas de código específicas haciendo click sobre la

flechita que aparece al pasar el cursor del mouse por un elemento del informe.

En el caso del informe de cobertura, si ahora regresamos al archivo de código (o hacemos click

en la flechita desde el propio informe), veremos que aparecen resaltadas las líneas de código que

se han ejecutado en el test y las que quedan por testear.

4.4. Ejecutar los tests desde línea de comando

Tal y como hemos comentado al ejecutar Jazzy, Xcode ofrece una utilidad de línea de comando

(xcodebuild) que permite realizar tareas como la ejecución de tests desde línea de comando.

Esto como veremos resultará de utilidad para ejecutar los tests en un servidor de integración

continua (Jenkins o Travis).

Los tests pueden ejecutarse con la siguiente línea de comando:

xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES

En esta línea de comando se indica que primero se haga un clean de proyecto y a continuación

se ejecuten los tests. Se proporciona la ubicación del proyecto, el esquema a ejecutar y el

dispositivo en el que se ejecutarán. Se utilizará la configuración de debug con la cobertura de

código activada.

La ejecución de este comando inicia el simulador de iOS indicado, donde se ejecutarán todos los

tests. Una vez finalizado, el simulador se cierra.

Aunque xcodebuild nos muestra el resultado de la ejecución de los tests en la consola, puede ser

de utilidad generar un informe más visual donde podamos ver qué tests fallan y donde. Para ello

podemos utilizar xcpretty

Para instalar xcpretty debemos ejecutar:

A continuación deberemos ejecutar xcodebuild pero haciendo un pipe de su salida mediante

xcpretty:

xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES |

xcpretty

Veremos que el resultado por consola ahora es más visual.

Podemos guardar la salida original de consola de xcodebuild haciendo un pipe con la utilidad tee,

de modo que el comando sería:

xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES | tee

xcodebuild.log | xcpretty

Finalmente, podemos generar un informe en formato Junit (que es de utilidad en Jenkins)

mediante el comando:

xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES | tee

xcodebuild.log | xcpretty -r junit

El informe se almacena en build/reports/junit.xml

Por otro lado, si lo preferís, podéis generar un informe en formato web, sustituyendo junit por

html en el comando anterior

xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES | tee

xcodebuild.log | xcpretty -r html

4.3. Cobertura de código desde línea de comando

Tras ejecutar los tests en un terminal, es posible generar un informe de cobertura desde línea de

comandos mediante Slather.

Slather es una utilidad que podemos instalar y permite transformar los datos de cobertura

obtenidos a un formato que sea legible (formato xml para el plugin de Cobertura en Jenkins,

formato para coveralls o bien formato html para generar el informe en formato web).

Para instalar Slather, debe ejecutarse la siguiente línea de comando:

http://buegling.com/blog/2015/4/26/building-nokogiri-on-os-x.

sudo gem install nokogiri -v 1.6.3.1 -- --with-iconv-dir=`xcode-select -

p`/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr --with-xml2-

include=`xcode-select -

p`/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/libxml

2

Una vez tengamos slather instalado, podemos obtener el informe de cobertura siguiendo estos

pasos:

1. Abrir una ventana de terminal

2. Ejecutar en la ventana de terminal los tests por línea de comando tal y como hemos visto

3. Ejecutar slather del siguiente modo:

/usr/local/bin/slather coverage --html --scheme swiftProtocolsAndGenerics

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj

Tras la ejecución, en la carpeta html tendremos el informe en formato html

En la web oficial de slather hay más información para generar el informe en otros formatos

(Cobertura, el cual utilizaremos con Jenkins y Coveralls, el cual utilizaremos con Travis).

5. Integración continua

Aunque la configuración de los tests y la cobertura sólo necesario realizarla una sola vez, puede

ser tedioso tener que ejecutar manualmente los tests y generar manualmente el informe e

cobertura cada vez que se hace un cambio en el código.

Por otro lado, a medida que un proyecto crece, puede ser incómodo ejecutar todos los tests del

proyecto cada vez que se hace un commit en el repositorio, ya que la ejecución de todos los tests

puede tomar demasiado tiempo.

En estos casos un servidor de integración continua puede ser de utilidad para automatizar la

ejecución de todos los tests, generación de informes o artefactos compilados cada vez que se

haga un push en el repositorio. De modo que el desarrollador sólo tiene que preocuparse de

desarrollar y testear su parte del código y el servidor se encarga de comprobar que la contribución

de un desarrollador en un equipo de trabajo (mediante un push o pull request) es correcta

mediante la ejecución de todos los tests. Todo esto sin interrumpir el flujo de trabajo del

desarrollador.

En este workshop veremos dos servicios de integración continua:

Travis-CI: travis CI es un servicio de integración continua en el cloud que se integra con github

de modo que cada vez que se hace un push en el repositorio realiza las tareas que se le indiquen.

Travis-CI es gratuito para proyectos open source en github.

Jenkins: es un servidor open source de integración continua. En visual disponemos

de http://jenkins.oficina.visual-engin.com

5.1. Configuración de Travis-CI

Para utilizar travis, es necesario configurar vuestra cuenta de github para proporcionarle acceso

a travis.

Para ello en la página de github, id a vuestra cuenta y entrad en la sección de integraciones:

Os aparecerán un montón de servicios que pueden integrarse con github. Seleccionad travis (más

adelante también configuraremos coveralls).

Seleccionar el botón verde (a mí me aparece configure porque ya lo tengo añadido en github).

Otorgamos los permisos necesarios a Travis para acceder a nuestra cuenta de github

Tras otorgar permisos a Travis para acceder a github, debemos añadir el repositorio que nos

interesa a travis.

Desde la pantalla principal de Travis, pulsamos en el botón + al lado de "My repositories" o sobre

el nombre de nuestra cuenta.

Desde la pantalla de nuestra cuenta, pulsamos en el botón de sincronización para refrescar la

lista de repositorios que hay en nuestra cuenta de github, y a continuación activamos el

repositorio que nos interese.

A partir de este momento, travis escuchará el repositorio indicado para iniciar la ejecución de los

tests cada vez que se suban cambios al repositorio.

Sólo falta indicarle a travis qué es lo que debe ejecutar.

Para configurar travis es necesario definir el archivo .travis.yml en la raíz del repositorio.

.travis.yml

language: objective-c

osx_image: xcode8.1

script:

- xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES

En el archivo indicamos que vamos a utilizar como lenguaje de programación objective-c (aunque

también sirve para Swift). Especificamos que deseamos una imagen de sistema operativo con

xcode8.1, y a continuación indicamos la línea de comando que deseamos ejecutar para pasar los

tests.

Finalmente, para que travis tenga acceso al esquema del proyecto que le hemos indicado

mediante línea de comando, debemos asegurarnos que el esquema esté marcado como "shared"

en Xcode. Para ello debemos editar el esquema y asegurarnos que el check "shared" esté activado

5.5.1. Archivo Readme y badges

Github por defecto nos crea un archivo README.md en el que podemos escribir documentación

del proyecto en formato markdown. Esta información es la que aparece en la página web de

github y puede utilizarse para poner documentación, intrucciones de uso, etc.

En el caso de travis (y también sucede igual con Coveralls y otros servicios), podemos además

añadir un badge que nos indique en todo momento el estado de los testa del proyecto (si pasan

o fallan), para que así de un vistazo podamos saber en todo momento el estado del proyecto.

Para ello debemos hacer click en el badge del proyecto en la web de travis (que inicialmente tiene

estado unknown) y copiar la URL del badge en formato markdown.

Modificamos o creamos el archivo README.md en la raíz del repositorio y añadimos el código

markdown que hemos copiado.

# swift-protocols-and-generics-workshop

Workshop for Swift protocols &amp; generics

[![Build Status](https://travis-ci.org/albertoirurueta/swift-protocols-and-

generics-workshop.svg?branch=master)](https://travis-

ci.org/albertoirurueta/swift-protocols-and-generics-workshop)

A partir de ahora en la web de github aparecerá el badge de estado de compilación. Lo podéis

comprobar en:

https://github.com/albertoirurueta/swift-protocols-and-generics-workshop

En cuanto realicemos un push en la rama master del repositorio, Travis pondrá nuestro push en

cola hasta que haya una máquina disponible para iniciar la ejecución de los tests. Podemos

comprobar desde la web de travis el estado de la ejecución, la consola de terminal con los

comandos que se han ejecutado, y desde la web de github veremos el estado de la compilación

y ejecución de los tests.

5.2. Configuración de Coveralls con Travis-CI

Del mismo modo que hemos hecho con travis, desde la web de Github, accedemos a integraciones

en nuestra cuenta y añadimos la integración con Coveralls.

Una vez concedido el acceso a nuestra cuenta de Github, en la web de coveralls, vamos a la

sección de repositorios

Sincronizamos los repositorios, y activamos el acceso al repositorio de interés.

Para generar el informe de cobertura en Coveralls, necesitaremos convertir los datos de cobertura

generados por xcodebuild a un formato que entienda coveralls, para ello utilizaremos Slather.

Para utilizar Slather, modificaremos el archivo .travis.yml para instalar slather en la máquina y

ejecutarlo tras la ejecución de los tests

.travis.yml

language: objective-c

osx_image: xcode8.1

before_install:

- gem install slather --no-ri --no-rdoc

script:

- xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES

- slather

A continuación, debemos crear un archivo .slather.yml para que slather sepa la configuración que

debe utilizar para enviar los datos de cobertura a coveralls

.slather.yml

input_format: profdata

coverage_service: coveralls

xcodeproj: ./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj

scheme: swiftProtocolsAndGenerics

Finalmente, modificaremos el archivo README.md para añadir un badge con información sobre

la cobertura.

La URL del badge de coveralls puede obtenerse en la propia web de coveralls, pulsando sobre el

botón embed al lado del icono del badge y copiando la URL de markdown en nuestro archivo

README.md

Por lo que el archivo README.md quedaría como se muestra a continuación:

README.md

# swift-protocols-and-generics-workshop

Workshop for Swift protocols &amp; generics

[![Build Status](https://travis-ci.org/albertoirurueta/swift-protocols-and-

generics-workshop.svg?branch=master)](https://travis-

ci.org/albertoirurueta/swift-protocols-and-generics-workshop)

[![Coverage Status](https://coveralls.io/repos/github/albertoirurueta/swift-

protocols-and-generics-

workshop/badge.svg?branch=master)](https://coveralls.io/github/albertoirurueta

/swift-protocols-and-generics-workshop?branch=master)

Ahora sólo es necesario realizar un push, y automáticamente Travis ejecutará los tests y enviará

la información de cobertura a Coveralls, y podremos acceder a ambos desde nuestra página de

github.

5.3. Publicación de informes en github-pages

Tal y como hemos visto en local, podemos generar informes de documentación, cobertura, tests

en formato HTML. Sin embargo sería conveniente tener disponibles dichos informes directamente

en la página web de nuestro proyecto.

Por suerte, github permite publicar páginas web estáticas en la rama gh-pages, de modo que

todo lo que se suba a esa rama aparecerá en la web de github.

En la siguientes secciones veremos cómo podemos hacer que travis genere los informes y a

continuación los suba a github pages para así tenerlos disponibles en la web de nuestro

repositorio.

5.3.1. Configuración para publicar automáticamente en github-pages desde Travis

Para poder utilizar github-pages deberemos poder hacer pushes en la rama gh-pages desde

Travis, utilizando pasos similares a los indicados aquí:

https://gist.github.com/domenic/ec8b0fc8ab45f39403dd.

Para ello deberemos dar acceso a nuestro repositorio a Travis, lo cual implica proporcionar un

usuario y contraseña o una clave SSH. Por seguridad, y más teniendo en cuenta que es un

repositorio open source público, utilizaremos una funcionalidad de travis para almacenar la clave

de forma segura en el repositorio.

Primero necesitaremos crear una clave SSH. En la documentación de github se indica cómo

hacerlo:

https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/

Los pasos a seguir son los siguientes:

1. Crear una clave SSH en local. Utilizaremos el mismo correo electrónico de nuestra cuenta de

github al crear la clave.

Indicamos la ubicación donde guardar la clave (puede usarse la ubicación por defecto) y

es importante no asignarle contraseña, ya que de lo contrario el comando ssh-add que

ejecutará Travis requeriría introducirla manualmente. Este comando creará un archivo de clave

privada y uno de clave pública.

No es necesario añadir la clave al agente SSH tal y como indica la documentación de Github ya

que no la usaremos en local para conectarnos a Github, si no que será Travis el que lo hará, por

lo que el comando ssh-add lo ejecutará Travis.

2. Añadir en la web de Github la clave pública generada para tener acceso. Cuidado, la clave debe

añadirse únicamente al repositorio que queremos dar acceso, no a nuestra cuenta, ya que

entonces daríamos acceso a Travis todos los respositorios. Para ello vamos a los settings del

repositorio.

En la sección de opciones veremos que más abajo hay la opción para activar github-pages e

incluso un editor online de las páginas. Nos aseguramos de que se usa la rama gh-pages o bien

usamos la herramienta de generación de una página de inicio mediante el botón Launch

automatic page generator.

3. Vamos a la sección de claves y pulsamos en el botón para añadir una clave.

4. Asignamos un nombre que identifique a la clave, le proporcionamos acceso de escritura, copiamos

el contenido de la clave pública y la añadimos

5. Veremos una confirmación conforme la clave se ha añadido.

6. Copiamos los archivos de claves pública y privada en el repositorio si no lo habíamos hecho ya

(ojo, no hacer commit aún ya que primero hay que encriptar la clave privada).

7. Comprobamos que ruby está instalado (por defecto en macOS ya viene instalado)

8. Instalamos el cliente de Travis (https://github.com/travis-ci/travis.rb) ejecutando el siguiente

comando.

Podemos comprobar que travis se ha instalado ejecutando el comando:

9. Desde la carpeta donde está la clave privada dentro del repositorio (el archivo github_key)

encriptamos la clave privada con el siguiente comando:

Si es la primera vez que ejecutamos Travis en el repositorio, travis nos lo indicará y nos

preguntará si es correcto. Travis nos devolverá el comando que es necesario para desencriptar

el archivo .enc generado. Debemos anotarlo ya que lo necesitaremos más adelante.

openssl aes-256-cbc -K $encrypted_0d0cc787d66b_key -iv

$encrypted_0d0cc787d66b_iv -in github_key.enc -out github_key -d

10. Veremos que se ha creado el archivo github_key.enc que contiene el archivo github_key pero

encriptado, por lo que podemos borrar el archivo github_key original, ya que únicamente

subiremos al repositorio en archivo github_key.enc.

11. Modificamos el archivo .travis.yml para añadir variables de entorno con los valores para

desencriptar la clave privada, y añadimos el comando ./publish-gh-pages.sh para ejecutar un

script que crearemos para publicar en github-pages

.travis.yml

language: objective-c

osx_image: xcode8.1

env:

global:

- ENCRYPTION_LABEL: "0d0cc787d66b"

- COMMIT_AUTHOR_EMAIL: "[email protected]"

before_install:

- gem install slather --no-ri --no-rdoc

script:

- xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES

- slather

- ./publish-gh-pages.sh

https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables

12. Creamos el archivo de script publish-gh-pages.sh

13. Otorgamos permisos de ejecución al archivo de script que hemos creado, de lo contrario

Travis no podrá ejecutarlo

1. Creamos un token de acceso en la cuenta de github, para ello vamos a settings pulsando sobre

la imagen de nuestra cuenta.

2. Seleccionamos la opción de Personal access tokens y pulsamos el botón de generar un nuevo

token. Asignamos un nombre al token y los permisos que le queremos dar (sólo de acceso a los

repositorios)

3. Copiamos el token devuelto por github, ya que no lo podremos consultar más adelante.

Desde el directorio del repositorio ejecutamos por línea de comando lo siguiente:

Este comando se encarga de generar un string encriptado mediante travis. Este string lo podemos

luego poner como una variable de entorno en el archivo .travis.yml, para ello debemos copiar la

respuesta de este comando en el archivo .travis.yml, tal y como se muestra a continuación:

.travis.yml

language: objective-c

osx_image: xcode8.1

env:

global:

-

secure: "l7sVCVmEoGW+NMQkx6F7XFM7HXVhrmDGE5mwqHNy2qZ/zkOOFvhh2/fbxiCDsW

6D4cGUuoiwtp+aL5I7x/R2RfLU4KEDnuk+Nu8OwEXKpdXlNKCt/sbjokrJieuhyufHFpD6d2

fGKU0ekczoOns9Vvl0Sa8MILaffEsW8R8cEMYC6jReb0d9el/CfFb/4N9R2gEK5zXi9v2z48

AvOZrjogCBoJNmVup8gtSTjbnJWo431FSlF8dlFS7bhemn/cKBfLEvyK4bhlLogYgGAwH5OE

p1LcwEWzGIKQ9nv8Ithr89DoG2YG48/n+vD2fpRaThuBjnHFmLvaTwGj0GWcGjrk+xkrkch0

tfqnO2sGpDM+B/ApZvom/CC71kSCvYWnFW5fRcXsXF6atvwbgP7iKlw/Ju66WewF7wANgyK3

hguhDy2RSUgUTYDvMuH8KpxmI6FcciN0GB0fHsxG9mf2laGNzLFzqO329RmXKHkxdV1wD/FO

S3498z9XyDulu/AvWdU73tvOEgPeqCTwEXkV8tP5bEqxfvfauioWTxFuwo6kjHUjPqvqOAE4

zSFB/k9XdHfV8OSJyfNh0+MoHWFBspHhqIErX3JnlFhfPvJhyJyWBJU2ViX8/WOCEkrog+Hm

Z/Sal5mUz8eRraqVVn4IFq1t8oP48ZOkAjM3am+8uuQpM="

- ENCRYPTION_LABEL: "0d0cc787d66b"

- COMMIT_AUTHOR_EMAIL: [email protected]

before_install:

- gem install slather --no-ri --no-rdoc

- gem install jazzy --no-ri --no-rdoc

- gem install xcpretty --no-ri --no-rdoc

script:

- set -o pipefail && xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS

Simulator,name=iPhone 7' TEST_AFTER_BUILD=YES -configuration Debug -

enableCodeCoverage=YES | tee xcodebuild.log | xcpretty -r html

- ./publish-gh-pages.sh

after_success:

- cd $TRAVIS_BUILD_DIR && slather

Una vez hecho este cambio tendremos acceso a la variable de entorno GITHUB_OAUTH_TOKEN

desencriptada sin necesidad de subir el token de forma pública a nuestro repositorio

A continuación, cambiamos la última línea del script publish-gh-pages.sh para realizar el push

mediante https utilizando un usuario con acceso al repositorio (no copiar el que hay aquí) y el

token desencriptado en la variable de entorno GITHUB_OAUTH_TOKEN como contraseña.

Con estos pasos ya estaría todo configurado para que Travis subiera los informes que indiquemos

en la función doStuff en gihub-pages

5.3.1. Publicación de informes de documentación de Jazzy en github-pages

Ya hemos visto cómo generar informes web de documentación mediante Jazzy, ahora vamos a

modificar la función doStuff en el archivo publish-gh-pages para que Travis los genere y los

publique en github-pages.

Puesto que utilizamos jazzy, también tendremos que modificar el archivo .travis.yml para indicarle

a travis que debe instalar jazzy

.travis.yml

language: objective-c

osx_image: xcode8.1

env:

global:

-

secure: "l7sVCVmEoGW+NMQkx6F7XFM7HXVhrmDGE5mwqHNy2qZ/zkOOFvhh2/fbxiCDsW6D4cGUu

oiwtp+aL5I7x/R2RfLU4KEDnuk+Nu8OwEXKpdXlNKCt/sbjokrJieuhyufHFpD6d2fGKU0ekczoOns

9Vvl0Sa8MILaffEsW8R8cEMYC6jReb0d9el/CfFb/4N9R2gEK5zXi9v2z48AvOZrjogCBoJNmVup8g

tSTjbnJWo431FSlF8dlFS7bhemn/cKBfLEvyK4bhlLogYgGAwH5OEp1LcwEWzGIKQ9nv8Ithr89DoG

2YG48/n+vD2fpRaThuBjnHFmLvaTwGj0GWcGjrk+xkrkch0tfqnO2sGpDM+B/ApZvom/CC71kSCvYW

nFW5fRcXsXF6atvwbgP7iKlw/Ju66WewF7wANgyK3hguhDy2RSUgUTYDvMuH8KpxmI6FcciN0GB0fH

sxG9mf2laGNzLFzqO329RmXKHkxdV1wD/FOS3498z9XyDulu/AvWdU73tvOEgPeqCTwEXkV8tP5bEq

xfvfauioWTxFuwo6kjHUjPqvqOAE4zSFB/k9XdHfV8OSJyfNh0+MoHWFBspHhqIErX3JnlFhfPvJhy

JyWBJU2ViX8/WOCEkrog+HmZ/Sal5mUz8eRraqVVn4IFq1t8oP48ZOkAjM3am+8uuQpM="

- ENCRYPTION_LABEL: "0d0cc787d66b"

- COMMIT_AUTHOR_EMAIL: "[email protected]"

before_install:

- gem install slather --no-ri --no-rdoc

- gem install jazzy --no-ri --no-rdoc

script:

- xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES

- slather

- ./publish-gh-pages.sh

Hacemos push y ahora Travis podrá generar el informe de documentación y publicarlo en la

carpeta docs de la rama gh-pages

5.3.2. Publicación de informes de tests de xcpretty en github-pages

Del mismo modo, tal y como hemos visto, podemos modificar doStuff en el archivo publish-gh-

pages para que Travis nos publique el informe de xcpretty en github-pages.

Para ello debemos modificar el archivo .travis.yml para que en lugar de ejecutar xcodebuild

directamente, haga un pipe con xcpretty tal y como hemos visto.

Para poder utilizar xcpretty le tendremos que decir a Travis que primero lo instale.

Además, para que el estado de build sea el correcto, tal y como se indica en la documentación

de xcpretty añadiendo set -o pipefail && antes del comando xcodebuild en el archivo .travis.yml,

tal. Puesto que se usa pipefail, ahora será necesario ejecutar slather por separado tras finalizar

el script correctamente, haciendo primero cd al directorio de compilación de Travis

.travis.yml

language: objective-c

osx_image: xcode8.1

env:

global:

-

secure: "l7sVCVmEoGW+NMQkx6F7XFM7HXVhrmDGE5mwqHNy2qZ/zkOOFvhh2/fbxiCDsW6D4cGUu

oiwtp+aL5I7x/R2RfLU4KEDnuk+Nu8OwEXKpdXlNKCt/sbjokrJieuhyufHFpD6d2fGKU0ekczoOns

9Vvl0Sa8MILaffEsW8R8cEMYC6jReb0d9el/CfFb/4N9R2gEK5zXi9v2z48AvOZrjogCBoJNmVup8g

tSTjbnJWo431FSlF8dlFS7bhemn/cKBfLEvyK4bhlLogYgGAwH5OEp1LcwEWzGIKQ9nv8Ithr89DoG

2YG48/n+vD2fpRaThuBjnHFmLvaTwGj0GWcGjrk+xkrkch0tfqnO2sGpDM+B/ApZvom/CC71kSCvYW

nFW5fRcXsXF6atvwbgP7iKlw/Ju66WewF7wANgyK3hguhDy2RSUgUTYDvMuH8KpxmI6FcciN0GB0fH

sxG9mf2laGNzLFzqO329RmXKHkxdV1wD/FOS3498z9XyDulu/AvWdU73tvOEgPeqCTwEXkV8tP5bEq

xfvfauioWTxFuwo6kjHUjPqvqOAE4zSFB/k9XdHfV8OSJyfNh0+MoHWFBspHhqIErX3JnlFhfPvJhy

JyWBJU2ViX8/WOCEkrog+HmZ/Sal5mUz8eRraqVVn4IFq1t8oP48ZOkAjM3am+8uuQpM="

- ENCRYPTION_LABEL: "0d0cc787d66b"

- COMMIT_AUTHOR_EMAIL: "[email protected]"

before_install:

- gem install slather --no-ri --no-rdoc

- gem install jazzy --no-ri --no-rdoc

- gem install xcpretty --no-ri --no-rdoc

script:

- set -o pipefail && xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES | tee

xcodebuild.log | xcpretty -r html

- ./publish-gh-pages.sh

after_success:

- cd $TRAVIS_BUILD_DIR && slather

Puesto que xcpretty guarda el resultado del informe en la carpeta build/reports, y el arcivo de

script publish-gh-pages.sh publica todo lo que hay en la carpeta out a github-pages, deberemos

modificar el archivo de script para mover el contenido de build/reports dentro de la carpeta out,

de este modo:

Ahora, tras realizar el push tendremos el informe de tests subido a github-pages.

5.3.3. Enlazar los informes de github-pages.

Aunque hemos creado los informes y los hemos publicado en github-pages, no los podemos ver

de forma cómoda porque no hay un enlace para verlos, para ello podemos modificar el archivo

index.html de github-pages o bien el archivo README.md para colocar un enlace a los informes.

README.md

# swift-protocols-and-generics-workshop

Workshop for Swift protocols &amp; generics

[![Build Status](https://travis-ci.org/albertoirurueta/swift-protocols-and-

generics-workshop.svg?branch=master)](https://travis-

ci.org/albertoirurueta/swift-protocols-and-generics-workshop)

[![Coverage Status](https://coveralls.io/repos/github/albertoirurueta/swift-

protocols-and-generics-

workshop/badge.svg?branch=master)](https://coveralls.io/github/albertoirurueta

/swift-protocols-and-generics-workshop?branch=master)

[Code Documentation](https://albertoirurueta.github.io/swift-protocols-and-

generics-workshop/docs/index.html)

[Test report](https://albertoirurueta.github.io/swift-protocols-and-generics-

workshop/build/reports/tests.html)

[Github pages](https://albertoirurueta.github.io/swift-protocols-and-generics-

workshop/)

5.4. Configuración de Jenkins

Hasta ahora hemos visto cómo configurar un servicio de integración continua en el cloud mediante

Travis, el cual se integra con Github y es gratuito para proyectos opensource.

Para proyectos privados esto no es una solución viable, (a no ser que tengamos cuentas de pago

en Github y Travis), pero es posible montar un servidor Jenkins para hacer exactamente lo mismo.

En Visual tenemos nuestro servidor Jenkins (http://jenkins.oficina.visual-engin.com).

Jenkins no es más que un servidor capaz de ejecutar scripts de forma programada (cada cierto

intervalo de tiempo o cuando hay un cambio en el repositorio) y de forma distribuida (ya que

puede ejecutar las tareas en nodos esclavos).

Jenkins es muy modular y configurable, y para ellos es posible instalarle una infinidad de plugins.

En nuestro caso necesitaremos los siguientes plugins (algunos ya vienen instalados por defecto):

SCM y GIT para obtener datos del repositorio

Junit: para analizar el archivo junit.xml generado por xcpretty con los resultados de los tests

Cobertura: para analizar el archivo xml de cobertura generado por slather

Publicación HTML: para publicar informes HTML

Para configurar el proyecto, los pasos a seguir son los siguientes:

1. Añadimos una tarea nueva con un proyecto de estilo libre.

2. Asignamos un nombre al proyecto.

3. Para no hace un uso excesivo de disco duro activamos desechar ejecuciones antiguas y

ponemos un número razonable de ejecuciones a mantener en disco (ej: 4)

4. Si el repositorio es github, podemos activar la casilla y poner la URL al repositorio. Esto nos

permitirá ir a la web del repo en github

5. Activar la casilla restringir donde se puede ejecutar el proyecto e indicad una máquina de un

nodo que esté previamente configurado en Jenkins.

6. En origen de fuente, seleccionamos git, introducimos la URL del repositorio e indicamos la

rama de la cual queremos obtener el código.

7. En disparadores de ejecuciones, podemos activar las casillas para detectar un cambio en

bitbucket o github, pero para que funcionen el servidor jenkins ha de ser accesible

públicamente (no es el caso en Visual), por lo que podemos activar la casilla para comprobar

el repositorio periódicamente (por ejemplo para comprobarlo cada 15 minutos debemos

introducir H/15 * * * *)

8. Es conveniente activar la casilla para detener la ejecución si se atasca. Esto es útil para que

Jenkins no deje el esclavo bloqueado indefinidamente en el caso de que algo falle (los tests

peten, se cierre el simulador, etc). De este modo, si no hay actividad por consola en un

determinado tiempo (ej: 5 minutos = 300 segundos), se detiene la ejecución.

9. En la sección de ejecutar, añadir un paso para ejecutar la linea de comandos (shell) y poner

los siguientes comandos de shell:

#ejecutar tests con informe en ./build/reports/junit.xml

xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES | tee

xcodebuild.log | /usr/local/bin/xcpretty -r junit

#generar documentación en ./docs/index.html

/usr/local/bin/jazzy --clean --author Alberto Irurueta --github_url

https://github.com/albertoirurueta/swift-protocols-and-generics-workshop --

xcodebuild-arguments -

project,./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj,-

scheme,swiftProtocolsAndGenerics --module swiftProtocolsAndGenerics --output

docs

#generar informe de cobertura

/usr/local/bin/slather coverage --cobertura-xml --output-directory ./coverage --

scheme swiftProtocolsAndGenerics

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj

/usr/local/bin/slather coverage --html --scheme swiftProtocolsAndGenerics

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj

10. En la sección de acciones para después, añadir:

a) Publicar informes de "cobertura". El archivo estará ubicado

en: coverage/cobertura.xml

b) Publicar los resultados de test de Junit. El archivo estará ubicado

en: build/reports/junit.xml

c) Publish HTML reports.

i. Informe de documentación de código.

Directorio: docs

Index page(s): index.html

Report title: Code Documentation

ii. Informe HTML de cobertura

Directorio: html

Index page(s): index.html

Report title: Coverage

Material de interés

Página oficial de Swift: https://swift.org (aquí encontraréis toda la documentación oficial de

Swift y el libro oficial en formato ebook en la sección de documentación donde encontraréis

información sobre Protocols).

Documentar código Swift: http://www.appcoda.com/swift-markdown/

Publicar documentación en github: http://www.jessesquires.com/swift-documentation/

Testing y cobertura de código en

Xcode: https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/

testing_with_xcode/chapters/07-code_coverage.html

Configurar Travis: https://www.raywenderlich.com/109418/travis-ci-tutorial

Instalar slather: https://github.com/SlatherOrg/slather

Generar informes web de los tests: https://github.com/fastlane/fastlane/tree/master/scan

Github pages: https://pages.github.com

Publicar de forma automática en Github-pages con

Travis: https://gist.github.com/domenic/ec8b0fc8ab45f39403dd

Integración continua y cobertura con Jenkins: https://pspdfkit.com/blog/2016/continuous-ios-

code-coverage-with-jenkins-and-slather/

Generar ipa's en Travis y distribuirlos con Testflight o HockeyApp: https://www.objc.io/issues/6-

build-tools/travis-ci/

NOTA: Aunque en este workshop no lo hemos visto, también es posible utilizar cocoapods con

Travis, para ello habría que descomentar las líneas comentadas mediante # en el siguiente

archivo de travis, y modificar la llamada de xcodebuild para que se utilice un workspace en lugar

de un proyecto

language: objective-c osx_image: xcode8.1 #cache: cocoapods before_install: #- gem install cocoapods --no-ri --no-rdoc - gem install slather --no-ri --no-rdoc script: - xcodebuild clean test -project

./swiftProtocolsAndGenerics/swiftProtocolsAndGenerics.xcodeproj -scheme

swiftProtocolsAndGenerics -destination 'platform=iOS Simulator,name=iPhone

7' TEST_AFTER_BUILD=YES -configuration Debug -enableCodeCoverage=YES - slather