簡體   English   中英

ios app如何“知道”運行單元測試

[英]How the ios app “knows” to run the unit tests

我知道我可以用xcodebuild開始我的應用程序的單元測試,但我想知道是什么告訴應用程序在啟動期間運行測試,它是一個發送到應用程序的特殊參數,還是以不同的方式編譯以運行測試(與XCTest)?

Xcode使用xctestRunTargetUnitTests腳本(來自/Developer/Tools/RunTargetUnitTests )進行單元測試。

xctestdynamic 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/RunTargetUnitTests.1.html#//apple_ref/doc/man/1/RunTargetUnitTests

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM