Xcode 4: ¿ejecuta pruebas desde la línea de comando(xcodebuild)?
unit-testing xcode4 (5)
Nota IMPORTANTE
Con Xcode 5.1 (quizás Xcode anterior también) la test
es una acción de compilación válida.
Pudimos reemplazar todo el truco de abajo con una llamada a xcodebuild usando la acción de compilación de prueba y con las opciones -destination
apropiadas. man xcodebuild
para más información.
La información a continuación se deja aquí para la posteridad
Intenté hackear los guiones de Apple para ejecutar pruebas unitarias como se menciona en
Ejecutar pruebas de unidad de Xcode 4 desde la línea de comando
y
Xcode4: ejecutar pruebas de aplicaciones desde la línea de comandos en iOS
y numerosas publicaciones similares en la web.
Sin embargo, me encontré con un problema con esas soluciones. Algunas de nuestras pruebas unitarias ejercieron el iOS Keychain y esas llamadas, cuando se ejecutan en el entorno que proviene de la piratería de las secuencias de comandos de Apple, fallaron con un error ( errSecNotAvailable
[-25291] para la morbosamente curiosa). Como resultado, las pruebas siempre fallaron ... una característica no deseada en una prueba.
Probé una serie de soluciones basadas en información que encontré en otro lugar en la web. Algunas de esas soluciones implicaban tratar de lanzar el daemon de servicios de seguridad del simulador de iOS, por ejemplo. Después de luchar con ellos, mi mejor opción parecía ser ejecutar en el simulador de iOS con todo el beneficio del entorno del simulador.
Lo que hice, entonces fue obtener la herramienta de inicio iOS Simulator ios-sim . Esta herramienta de línea de comandos utiliza marcos de Apple privados para iniciar una aplicación de iOS desde la línea de comandos. De particular uso para mí, sin embargo, fue el hecho de que me permite pasar las Variables de entorno y los Argumentos de línea de comando a la aplicación que está lanzando.
A pesar de las variables de entorno, pude obtener mi paquete de pruebas de unidad inyectado en mi aplicación. A través de los argumentos de la línea de comando, puedo pasar el "-SenTest All" necesario para que la aplicación ejecute las pruebas unitarias y salga.
Creé un Scheme (que llamé "CommandLineUnitTests") para mi lote de pruebas unitarias y marqué la acción "Ejecutar" en la sección de compilación como se describe en las publicaciones anteriores.
Sin embargo, en lugar de piratear los guiones de Apple, reemplacé el guión con uno que lanza la aplicación usando ios-sim y configura el entorno para inyectar el paquete de pruebas unitarias en la aplicación por separado.
Mi guión está escrito en Ruby, que es más familiar para mí que BASH scripting. Aquí está ese script:
if ENV[''SL_RUN_UNIT_TESTS''] then
launcher_path = File.join(ENV[''SRCROOT''], "Scripts", "ios-sim")
test_bundle_path= File.join(ENV[''BUILT_PRODUCTS_DIR''], "#{ENV[''PRODUCT_NAME'']}.#{ENV[''WRAPPER_EXTENSION'']}")
environment = {
''DYLD_INSERT_LIBRARIES'' => "/../../Library/PrivateFrameworks/IDEBundleInjection.framework/IDEBundleInjection",
''XCInjectBundle'' => test_bundle_path,
''XCInjectBundleInto'' => ENV["TEST_HOST"]
}
environment_args = environment.collect { |key, value| "--setenv #{key}=/"#{value}/""}.join(" ")
app_test_host = File.dirname(ENV["TEST_HOST"])
system("#{launcher_path} launch /"#{app_test_host}/" #{environment_args} --args -SenTest All #{test_bundle_path}")
else
puts "SL_RUN_UNIT_TESTS not set - Did not run unit tests!"
end
Ejecutando esto desde la línea de comando se ve así:
xcodebuild -sdk iphonesimulator -workspace iPhoneApp.xcworkspace/ -scheme "CommandLineUnitTests" clean build SL_RUN_UNIT_TESTS=YES
Después de buscar la variable de entorno SL_RUN_UNIT_TESTS
, la secuencia de comandos encuentra el "iniciador" (el ejecutable iOS-sim) dentro del árbol de código fuente del proyecto. A continuación, construye la ruta a mi paquete de pruebas de unidad en función de la configuración de compilación que Xcode pasa en las variables de entorno.
A continuación, creo el conjunto de variables de entorno de ejecución para mi aplicación en ejecución que inyectan el paquete de prueba de unidades. Configuré esas variables en el hash de environment
en el medio del script y luego utilicé un poco de ruby grunge para unirlas en una serie de argumentos de línea de comando para la aplicación ios-sim
.
Cerca de la parte inferior, tomo TEST_HOST
del entorno como la aplicación que deseo iniciar y el comando del system
realmente ejecuta ios-sim
pasando la aplicación, los argumentos del comando para configurar el ambiente y los argumentos -SenTest All
y la ruta del paquete de prueba a la aplicación en ejecución.
La ventaja de este esquema es que ejecuta las pruebas unitarias en el entorno del simulador tanto como yo creo que lo hace Xcode. La desventaja del esquema es que se basa en una herramienta externa para iniciar la aplicación. Esa herramienta externa utiliza frameworks privados de Apple, por lo que puede ser frágil con las posteriores versiones del sistema operativo, pero funciona por el momento.
PD: Usé mucho el "I" en este post por razones narrativas, pero gran parte del mérito recae en mi compañero en el crimen, Pawel, quien resolvió estos problemas conmigo.
Creé un nuevo proyecto de iOS en Xcode 4 e incluí pruebas unitarias. La aplicación predeterminada tiene 2 objetivos, la aplicación principal y el paquete de prueba de la unidad. El uso de "Producto> Prueba" (Command-U) construye la aplicación, construye el paquete de prueba de la unidad, inicia el simulador de iOS y ejecuta las pruebas. Ahora me gustaría poder hacer lo mismo desde la línea de comando. La herramienta de línea de comandos (xcodebuild) no tiene una acción de "prueba", pero parece que debería ser capaz de construir directamente el destino del paquete de prueba unitaria, ya que depende de la aplicación en sí. Sin embargo, corriendo:
xcodebuild -target TestAppTests -sdk iphonesimulator4.3 -configuration Debug build
da el siguiente mensaje:
/Developer/Platforms/iPhoneSimulator.platform/Developer/Tools/Tools/RunPlatformUnitTests:95: warning: Skipping tests; the iPhoneSimulator platform does not currently support application-hosted tests (TEST_HOST set).
Eso parece una mentira, ya que Test Host está configurado para mi objetivo de paquete de prueba de unidad cuando ejecuto Command-U desde la GUI. He visto publicaciones anteriores sobre la separación entre las pruebas lógicas y las pruebas de aplicación, pero parece que Xcode 4 elimina esa distinción. ¿Alguna pista de cómo puedo ejecutar mis pruebas desde la línea de comandos?
Es una solución incompleta, pero pude ejecutar compilaciones de lógica de línea de comandos en su propio esquema y objetivo de compilación: http://blog.carbonfive.com/2011/04/06/running-xcode-4-unit-tests- from-the-command-line /
Me inspiré en la publicación de Jonah y encontré una forma de hacerlo:
Básicamente, necesitas Xcode 4 y tienes que hackear un script para que funcione, pero lo hace.
El punto clave es convencer a Xcode 4 de que ejecute el paquete de prueba de iOS como si fuera un paquete de MacOS X: es un problema con la plataforma, Xcode no desea ejecutar pruebas de aplicaciones de manera inmediata en la línea de comandos. Gracioso, porque parece funcionar.
También hay un proyecto de muestra en el sitio.
lo que está buscando es este argumento no documentado (también necesita SDK y destino) para ejecutar sus Pruebas OCUnit desde la terminal
xcodebuild -target MyTarget -sdk iphonesimulator TEST_AFTER_BUILD=YES
xctool resuelve este problema: https://github.com/facebook/xctool
lo usamos en nuestro servidor de integración continua sin problemas