Cómo la aplicación ios "sabe" ejecutar las testings de la unidad

Sé que puedo comenzar las testings de unidades de mi aplicación con xcodebuild , pero me pregunto qué le dice a la aplicación que ejecute las testings durante el lanzamiento, ¿es un argumento especial enviado a la aplicación o se compiló de manera diferente para ejecutar las testings (con XCTest)?

Xcode usa el xctest y RunTargetUnitTests (desde /Developer/Tools/RunTargetUnitTests ) para las testings unitarias.

xctest inyecta dynamic library (kit de testing que tiene hilo por separado para sus trabajos) en su binary, la inyección le da acceso dylib a su memory de process (puede acceder a sus Clases / Instancias en su memory de process), y puede realizar llamadas y hacer testings unitarias Las devoluciones de llamada desde el dispositivo / simulador se reciben desde el depurador (no hay una técnica especial para la testing de unidades).

Simplemente dijo: El proyecto con el test scheme se comstack como de costumbre, pero está vinculando una biblioteca dinámica que trojará la memory de su process y realizará testings.

También información que será de gran ayuda:

RunUnitTests acepta ENVIRONMENT variables , aquí hay algunas interesantes de ellas

TEST_HOST : la ruta completa a un ejecutable en el que "inyectar" el package de testing de unidad especificado. Para una aplicación, esta debe ser la ruta completa a la aplicación dentro de su contenedor. No establezca esto para obras de frameworks o bibliotecas.

TEST_RIG : la ruta completa a un ejecutable para usar como plataforma de testing en lugar de CPlusTestRig o otest. El ejecutable debe tomar una ruta a un package de testing como su argumento final. Su DYLD_FRAMEWORK_PATH y DYLD_LIBRARY_PATH se configurarán para apuntar al BUILT_PRODUCTS_DIR antes de la ejecución. No configure esto si está utilizando uno de los equipos de testing pnetworkingeterminados.

además
BUNDLE_LOADER se utiliza como una opción de linker, lo que indica que el linker debe vincular la Testing dynamic library en su binary especificado.

Las templates de destino del package de testing tienen una fase de compilation del script de shell al final que invoca /Developer/Tools/RunUnitTests . RunUnitTests examina la configuration de compilation que se pasa a través de su entorno y determina a partir de esa información cómo ejecutar las testings en el package de testing.

Si está probando un marco, RunUnitTests ejecutará el equipo de testing apropiado y le indicará que cargue y ejecute las testings en su package. Dado que su package de testing debe vincularse con su marco, su marco se cargará cuando el equipo de testing cargue su package.

Si está probando una aplicación, debe especificar la aplicación como Test Host y Bundle Loader para su package de testing en la configuration de compilation de su configuration. La configuration del cargador de packages le dice al linker que vincule su package con la aplicación que lo carga como si la aplicación fuera un marco, lo que le permite referirse a classs y otros símbolos dentro de la aplicación de su package sin includelos en el package. La configuration Test Host le indica a RunUnitTests que inicie la aplicación especificada e inyecte su package de testing en él para ejecutar sus testings.

Para get más información, consulte páginas de RunTargetUnitTests / xctest

https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man1/RunTargetUnitTests.1.html#//apple_ref/doc/man/1/RunTargetUnitTests

https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man1/xctest.1.html

Aquí está el script RunTargetUnitTests

 bin

 #
 # Copyright (c) 2005-2013 Apple Inc. Todos los derechos reservados.
 #

 # Derechos de autor (c) 1997-2005, Sen: te (Sente SA).  Todos los derechos reservados.
 #
 # El uso de este código fuente se rige por la siguiente licencia:
 # 
 # Redistribución y uso en formularios fuente y binarys, con o sin modificación, 
 # están permitidos siempre que se cumplan las siguientes condiciones:
 # 
 # (1) Las networkingistribuciones del código fuente deben conservar el aviso de copyright anterior, 
 # esta list de condiciones y el siguiente descargo de responsabilidad.
 # 
 # (2) Las networkingistribuciones en forma binaria deben reproducir el aviso de copyright anterior, 
 # esta list de condiciones y la siguiente exención de responsabilidad en la documentation 
 # y / u otros materiales provistos con la distribución.
 # 
 # ESTE SOFTWARE ES PROPORCIONADO POR LOS TITULARES DE LOS DERECHOS DE AUTOR Y LOS CONTRIBUIDORES `` TAL CUAL '' 
 # Y CUALESQUIERA GARANTÍAS EXPRESAS O IMPLÍCITAS, INCLUIDAS, PERO NO LIMITADAS A, LAS IMPLÍCITAS 
 # SE RENUNCIA A LAS GARANTÍAS DE COMERCIABILIDAD E IDONEIDAD PARA UN PROPÓSITO PARTICULAR. 
 # EN NINGÚN CASO Sente SA O LOS COLABORADORES SERÁN RESPONSABLES POR NINGÚN DAÑO DIRECTO, INDIRECTO, INCIDENTAL, 
 # DAÑOS ESPECIALES, EJEMPLARES O CONSECUENCIALES (INCLUIDOS, PERO SIN LIMITARSE A, LA ADQUISICIÓN 
 # DE BIENES O SERVICIOS SUSTITUTOS;  PÉRDIDA DE USO, DATOS O BENEFICIOS;  O INTERRUPCIÓN DEL NEGOCIO) 
 # SIN EMBARGO, Y CUALQUIER TEORÍA DE RESPONSABILIDAD, YA SEA POR CONTRATO, RESPONSABILIDAD ESTRICTA, 
 # O AGRAVIO (INCLUYENDO NEGLIGENCIA O DE OTRO MODO) QUE SURJA DE CUALQUIER MANERA DEL USO DE ESTE SOFTWARE, 
 # AÚN SI SE HA ADVERTIDO DE LA POSIBILIDAD DE DICHO DAÑO.
 # 
 # Nota: esta licencia es equivalente a la licencia de FreeBSD.
 # 
 # Este aviso no se puede eliminar de este file.

 si ["$ {NATIVE_ARCH_ACTUAL}" = ""];  entonces
     NATIVE_ARCH_ACTUAL = `arch`
 fi

 si ["$ {ARCHS}" = ""];  entonces
     ARCHS = `arch`
 fi

 si ["$ {DEVELOPER_DIR}" = ""];  entonces
     DEVELOPER_DIR = "$ {SYSTEM_DEVELOPER_DIR}"
 fi 

 si ["$ {OTEST}" = ""];  entonces
     OTEST = "$ {DEVELOPER_DIR} / Tools / otest"
 fi

 si ["$ {OTEST_TARGET}" = ""];  entonces
     OTEST_TARGET = "$ {BUILT_PRODUCTS_DIR} / $ {FULL_PRODUCT_NAME}"
 fi

 RunTargetUnitTestsForArch () {
     echo "$ {DEVELOPER_DIR} / Tools / RunTargetUnitTests: 0: nota: Inicio de testings para $ {1}"

     si ["$ {DYLD_FRAMEWORK_PATH}" = ""];  entonces
         DYLD_FRAMEWORK_PATH = "$ {BUILT_PRODUCTS_DIR}: $ {DEVELOPER_DIR} / Library / Frameworks"
     más
         DYLD_FRAMEWORK_PATH = "$ {BUILT_PRODUCTS_DIR}: $ {DEVELOPER_DIR} / Library / Frameworks: $ {DYLD_FRAMEWORK_PATH}"
     fi

     exportar DYLD_FRAMEWORK_PATH

     echo "OTEST = $ {OTEST}"

     arch -arch "$ {1}" "$ {OTEST}" "$ {OTEST_TARGET}"

     desasignar DYLD_FRAMEWORK_PATH

     echo "$ {DEVELOPER_DIR} / Tools / RunTargetUnitTests: 0: note: Pruebas completadas para $ {1}"
 }

 SkipTargetUnitTestsForArch () {
     echo "$ {DEVELOPER_DIR} / Tools / RunTargetUnitTests: 0: note: Pruebas omitidas para $ {1}"
 }

 si ["$ {TEST_AFTER_BUILD}" = "SÍ"];  entonces
     # Ejecute las testings de unidad una vez por architecture requerida y admitida.
     para TEST_ARCH en $ {ARCHS};  hacer
         caso "$ {NATIVE_ARCH_ACTUAL}" en
         i386)
             si ["$ {TEST_ARCH}" = "i386"];  entonces
                 RunTargetUnitTestsForArch "$ {TEST_ARCH}"
             más
                 SkipTargetUnitTestsForArch "$ {TEST_ARCH}"
             fi
             ;;

         x86_64)
             si ["$ {TEST_ARCH}" = "i386" -o "$ {TEST_ARCH}" = "x86_64"];  entonces
                 RunTargetUnitTestsForArch "$ {TEST_ARCH}"
             más
                 SkipTargetUnitTestsForArch "$ {TEST_ARCH}"
             fi
             ;;

         *)
             RunTargetUnitTestsForArch "$ {TEST_ARCH}"
             ;;
         esac
     hecho
 fi

Sé cómo funcionaba con OCTest y supongo que XCTest funciona de manera similar.

Solía ​​ejecutar mis testings con WaxSim , que es una utilidad que accede a frameworks de simulador privados. El uso de WaxSim no es realmente importante aquí, solo nos permite inspeccionar los elementos internos.

El command ejecutar ejecutaba MyApp.app en el simulador. Para comenzar las testings, primero debes inyectarlas (¡se comstackn en un package por separado!). El command se veía así

 WaxSim \ -e DYLD_INSERT_LIBRARIES="$INJECTION_FRAMEWORK_PATH" \ -e XCInjectBundle="MyApp.octest" \ -e XCInjectBundleInto="MyApp.app/MyApp" \ MyApp.app \ -SenTest All 

Donde se definió INJECTION_FRAMEWORK_PATH así:

 XCODE_PATH=$( xcode-select --print-path ) PLATFORM_PATH="$XCODE_PATH/Platforms/iPhoneSimulator.platform" INJECTION_FRAMEWORK_PATH="$PLATFORM_PATH/Developer/Library/PrivateFrameworks/IDEBundleInjection.framework/IDEBundleInjection" 

Tenga en count también los parameters de la command-line -SenTest All al framework qué testings ejecutar.

Básicamente, la aplicación se ejecutaba como siempre, pero había otro package inyectado para ejecutar las testings una por una y luego salir de la aplicación completa.