在Xcode的unit testing,它运行的应用程序?

我遇到了一个我以前没遇到过的奇怪的问题。

当你做cmd + U来运行你的unit testing(例如OCUnit),它实际上调用main.m,新的appDelegate和运行应用程序,就好像你已经按下CMD + R?

我只问,因为我在这个DataLayer背后使用CoreData。 我在我的testing中嘲笑DataLayer成功,但是一旦我实现了一个实际调用CoreData的getAll方法,app / xcode抛出一个关于被pipe对象模型的exception不能为零。 我明白,但我没有意义,实际上新的DataLayer类,我已经在我的mainviewcontroller loadView方法中调用DataLayer的getAll方法放置一个断点。 testing无关紧要,因为这是一个模拟对象,但显然它是调用真实的实例。

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

该应用程序实际上运行,但有一个技巧,你可以用来阻止它运行。

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; } 

这里是Sulthan的答案的一个变体,它使用了XCTest 5生成的testing类的默认值XCTest。

 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"); } } } 

这将进入main.m,这应该在标准项目布局的支持文件下。

然后在你的testing目录中添加:

TestAppDelegate.h

 #import <Foundation/Foundation.h> @interface TestAppDelegate : NSObject<UIApplicationDelegate> @end 

TestAppDelegate.m

 #import "TestAppDelegate.h" @implementation TestAppDelegate @end 

在Swift中,我优先绕过application: didFinishLaunchingWithOptions的正常执行pathapplication: 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 } 

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

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

1:删除AppDelegate.swift中的@UIApplicationMain

2:创build一个空的TestingAppDelegate.swift

 import UIKit class TestingAppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? } 

3:创build一个名为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)) } 

是的,您的testing目标对应用目标具有目标依赖性,所以当您按Cmd + U或Cmd + Shift + U时,应用目标将被build立。

我使用Tomasz Bak的方法加上dwb答案的一些代码,并拿出以下内容:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { BOOL runningTests = NSClassFromString(@"XCTestCase") != nil; if (runningTests) { self.window.rootViewController = [UIViewController new]; return true; } // Your normal code below this .... } 

我发现了另一个解决问题的办法:

 int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, ({ ![NSProcessInfo processInfo].environment[@"XCTestConfigurationFilePath"] ? @"AppDelegate" : nil; })); } } 

从这里: http : //qualitycoding.org/app-delegate-for-tests/#comment-63984

使用xCode 7和xCtool

xctool能够在不运行应用程序的情况下执行unit testing。

为了得到这个工作,

1。 更新目标设置以在没有主机应用的情况下运行

select您的项目 – >然后testing目标 – >将主机应用程序设置为无。

在这里输入图像说明

2.安装xctool,如果你没有的话。

 brew install xctool 

3.使用xctool使用terminal运行testing。

 xctool -workspace yourWorkspace.xcworkspace -scheme yourScheme run-tests -sdk iphonesimulator 

上面的优秀答案build议在运行时dynamic更改应用程序委托。

我做的小修改是通过查询NSProcessInfo来检测unit testing运行 。 好处是你不需要有一个可以被检测到的类来看unit testing是否正在运行。

  int main(int argc, char * argv[]) { // Put your App delegate class here. const Class appDelegateClass = [ATAppDelegate class]; NSDictionary *const environmentDictionary = [[NSProcessInfo processInfo] environment]; const BOOL runningUnitTests = environmentDictionary[@"XCInjectBundleInto"] != nil; NSString *delegateName = runningUnitTests ? nil : NSStringFromClass(appDelegateClass); @autoreleasepool { return UIApplicationMain(argc, argv, nil, delegateName); } } 

@"XCInjectBundleInto"@"XCInjectBundleInto"属性是unit testing包的path,由Xcode设置。