[英]How the ios app “knows” to run the unit tests
我知道我可以用xcodebuild
開始我的應用程序的單元測試,但我想知道是什么告訴應用程序在啟動期間運行測試,它是一個發送到應用程序的特殊參數,還是以不同的方式編譯以運行測試(與XCTest)?
Xcode使用xctest
和RunTargetUnitTests
腳本(來自/Developer/Tools/RunTargetUnitTests
)進行單元測試。
xctest
將dynamic library
(測試工具包具有單獨的線程作為其作業)注入二進制文件,注入使dylib
訪問您的進程內存(它可以訪問您的進程內存中的類/實例),並且它能夠執行調用和make單元測試。 從調試器接收來自設備/模擬器的回調(沒有用於單元測試的特殊技術)。
簡單地說:帶有test scheme
的項目像往常一樣編譯,但是它會鏈接動態庫,它會使你的進程內存變成木馬並進行測試。
還有非常有用的信息:
RunUnitTests
接受ENVIRONMENT variables
,這里有一些有趣的ENVIRONMENT variables
TEST_HOST
- 可“注入”指定單元測試包的可執行文件的完整路徑。 對於應用程序,它必須是其包裝器中應用程序的完整路徑。 不要為框架作品或庫設置此項。
TEST_RIG
- 可用作測試裝備而不是CPlusTestRig或otest的可執行文件的完整路徑。 可執行文件必須將測試包的路徑作為其最終參數。 其DYLD_FRAMEWORK_PATH和DYLD_LIBRARY_PATH將配置為在執行之前指向BUILT_PRODUCTS_DIR。 如果您使用其中一個默認測試裝備,請不要設置此項。
也
BUNDLE_LOADER
用作鏈接器選項,指示將Testing dynamic library
鏈接到指定二進制文件的鏈接器。
測試包目標模板在最后調用/Developer/Tools/RunUnitTests
的shell腳本構建階段。 RunUnitTests查看它通過其環境傳遞的構建設置,並根據該信息確定如何在測試包中運行測試。
如果您正在測試框架,RunUnitTests將運行相應的測試裝備並告訴它加載並運行捆綁中的測試。 由於您的測試包應鏈接到您的框架,因此當測試裝置加載您的包時,您的框架將被加載。
如果您正在測試應用程序,則需要在其配置的構建設置中將應用程序指定為測試包的測試主機和分發包加載器。 Bundle Loader設置告訴鏈接器將您的bundle與正在加載它的應用程序鏈接,就像應用程序是一個框架一樣,允許您從bundle中引用應用程序中的類和其他符號,而不實際將它們包含在bundle中。 “測試主機”設置告訴RunUnitTests啟動指定的應用程序並將測試包注入其中以運行其測試。
有關更多信息,請參閱RunTargetUnitTests
/ xctest
man
頁
https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man1/xctest.1.html
這是RunTargetUnitTests
腳本
#!/bin/sh # # Copyright (c) 2005-2013 Apple Inc. All rights reserved. # # Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. # # Use of this source code is governed by the following license: # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # (1) Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # (2) Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Note: this license is equivalent to the FreeBSD license. # # This notice may not be removed from this file. if [ "${NATIVE_ARCH_ACTUAL}" = "" ]; then NATIVE_ARCH_ACTUAL=`arch` fi if [ "${ARCHS}" = "" ]; then ARCHS=`arch` fi if [ "${DEVELOPER_DIR}" = "" ]; then DEVELOPER_DIR="${SYSTEM_DEVELOPER_DIR}" fi if [ "${OTEST}" = "" ]; then OTEST="${DEVELOPER_DIR}/Tools/otest" fi if [ "${OTEST_TARGET}" = "" ]; then OTEST_TARGET="${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" fi RunTargetUnitTestsForArch() { echo "${DEVELOPER_DIR}/Tools/RunTargetUnitTests:0: note: Starting tests for ${1}" if [ "${DYLD_FRAMEWORK_PATH}" = "" ] ; then DYLD_FRAMEWORK_PATH="${BUILT_PRODUCTS_DIR}:${DEVELOPER_DIR}/Library/Frameworks" else DYLD_FRAMEWORK_PATH="${BUILT_PRODUCTS_DIR}:${DEVELOPER_DIR}/Library/Frameworks:${DYLD_FRAMEWORK_PATH}" fi export DYLD_FRAMEWORK_PATH echo "OTEST=${OTEST}" arch -arch "${1}" "${OTEST}" "${OTEST_TARGET}" unset DYLD_FRAMEWORK_PATH echo "${DEVELOPER_DIR}/Tools/RunTargetUnitTests:0: note: Completed tests for ${1}" } SkipTargetUnitTestsForArch() { echo "${DEVELOPER_DIR}/Tools/RunTargetUnitTests:0: note: Skipped tests for ${1}" } if [ "${TEST_AFTER_BUILD}" = "YES" ]; then # Run the unit tests once per requested and supported architecture. for TEST_ARCH in ${ARCHS}; do case "${NATIVE_ARCH_ACTUAL}" in i386) if [ "${TEST_ARCH}" = "i386" ]; then RunTargetUnitTestsForArch "${TEST_ARCH}" else SkipTargetUnitTestsForArch "${TEST_ARCH}" fi ;; x86_64) if [ "${TEST_ARCH}" = "i386" -o "${TEST_ARCH}" = "x86_64" ]; then RunTargetUnitTestsForArch "${TEST_ARCH}" else SkipTargetUnitTestsForArch "${TEST_ARCH}" fi ;; *) RunTargetUnitTestsForArch "${TEST_ARCH}" ;; esac done fi
我知道它是如何與OCTest一起工作的,我認為XCTest以類似的方式工作。
我曾經使用WaxSim
運行我的測試, WaxSim
是一個訪問私有模擬器框架的實用程序。 在這里使用WaxSim
並不重要,它只是讓我們檢查內部。
run命令在模擬器中運行MyApp.app
。 要開始測試,首先必須注入它們(它們被編譯為單獨的包!)。 命令看起來像這樣
WaxSim \
-e DYLD_INSERT_LIBRARIES="$INJECTION_FRAMEWORK_PATH" \
-e XCInjectBundle="MyApp.octest" \
-e XCInjectBundleInto="MyApp.app/MyApp" \
MyApp.app \
-SenTest All
INJECTION_FRAMEWORK_PATH
定義如下:
XCODE_PATH=$( xcode-select --print-path )
PLATFORM_PATH="$XCODE_PATH/Platforms/iPhoneSimulator.platform"
INJECTION_FRAMEWORK_PATH="$PLATFORM_PATH/Developer/Library/PrivateFrameworks/IDEBundleInjection.framework/IDEBundleInjection"
另請注意-SenTest All
命令行參數,它們告訴框架要運行哪些測試。
基本上,應用程序一如既往地運行,但是注入了另一個bundle來逐個運行測試,然后退出整個應用程序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.