Xcode中的单元测试,是否运行应用程序?

Mar*_*k W 45 iphone xcode unit-testing ios

我遇到了一个我之前没遇到的奇怪问题.

当您执行cmd + U运行单元测试(例如OCUnit)时,它是否实际调用main.m,新建appDelegate并运行应用程序,就像您按下了cmd + R一样?

我只是问,因为我在这个DataLayer后面使用CoreData.我在我的测试中成功地模拟了DataLayer,但是一旦我实现了一个实际调用CoreData的getAll方法,app/xcode抛出一个关于托管对象模型的异常不能为零.我明白这一点,但我并不是想要实际创建DataLayer类,我在mainviewcontroller loadView方法中设置了一个断点,它调用了DataLayer getAll方法.它与测试无关,因为它是一个模拟对象,但它显然是在调用真实实例.

所以回到我的问题,当按下cmd + U时,它还运行应用程序然后运行测试?

Sul*_*han 64

该应用程序实际上是运行的,但有一个技巧可以用来防止它运行.

int main(int argc, char* argv[]) {
    int returnValue;

    @autoreleasepool {
        BOOL inTests = (NSClassFromString(@"SenTestCase") != nil
                     || NSClassFromString(@"XCTest") != nil);    

        if (inTests) {
            //use a special empty delegate when we are inside the tests
            returnValue = UIApplicationMain(argc, argv, nil, @"TestsAppDelegate");
        }
        else {
            //use the normal delegate 
            returnValue = UIApplicationMain(argc, argv, nil, @"AppDelegate");
        }
    }

    return returnValue;
}
Run Code Online (Sandbox Code Playgroud)

  • 对于XCODE 5 - BOOL inTests =(NSClassFromString(@"XCTest")!= nil); (2认同)

dwb*_*dwb 20

这是Sulthan使用XCTest的答案的变体,XCTest是XCode 5生成的测试类的默认值.


int main(int argc, char * argv[])
{
    @autoreleasepool {
        BOOL runningTests = NSClassFromString(@"XCTestCase") != nil;
        if(!runningTests)
        {
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
        else
        {
            return UIApplicationMain(argc, argv, nil, @"TestAppDelegate");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将进入main.m,它应位于标准项目布局中的Supporting Files下.

然后在您的测试目录中添加:

TestAppDelegate.h


#import <Foundation/Foundation.h>

@interface TestAppDelegate : NSObject<UIApplicationDelegate>
@end
Run Code Online (Sandbox Code Playgroud)

TestAppDelegate.m


#import "TestAppDelegate.h"

@implementation TestAppDelegate
@end
Run Code Online (Sandbox Code Playgroud)


Tom*_*Bąk 10

在Swift中,我优先绕过内部的正常执行路径application: didFinishLaunchingWithOptions:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    guard normalExecutionPath() else {
        window = nil
        return false
    }

    // regular setup

    return true
}

private func normalExecutionPath() -> Bool {
    return NSClassFromString("XCTestCase") == nil
}
Run Code Online (Sandbox Code Playgroud)

内部代码guard将删除从故事板创建的任何视图.


Rém*_*rin 5

如果您正在使用Swift(您可能没有main.c),则必须执行以下步骤:

1:除去@UIApplicationMainAppDelegate.swift

2:创建一个空的 TestingAppDelegate.swift

import UIKit
class TestingAppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
}
Run Code Online (Sandbox Code Playgroud)

3:创建一个名为的文件main.swift:

import Foundation
import UIKit

let isRunningTests = NSClassFromString("XCTestCase") != nil

if isRunningTests {
   UIApplicationMain(C_ARGC, C_ARGV, nil, NSStringFromClass(TestingAppDelegate))
} else {
   UIApplicationMain(C_ARGC, C_ARGV, nil, NSStringFromClass(AppDelegate))
}
Run Code Online (Sandbox Code Playgroud)

  • XCode 7(beta 5)+ iOS9 - 使用Process.argc,Process.unsafeArgv代替C_ARGC,C_ARGV (3认同)