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.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 & 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 & 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
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 & 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