我遇到了一个我以前没遇到过的奇怪问题。
当您执行cmd + U运行单元测试(例如OCUnit)时,它是否实际调用main.m,新建了appDelegate并运行应用程序,就像您按下了cmd + R一样?
我只是问,因为我在这个DataLayer后面使用了CoreData。我在我的测试中成功地模拟了DataLayer,但是一旦我实现了一个实际调用CoreData的getAll方法,app / xcode抛出了一个关于托管对象模型的例外不能为零。我理解这一点,但我并没有意义地实际创建DataLayer类,并且我在我的mainviewcontroller loadView方法中设置了一个断点,它调用了DataLayer getAll方法。它不应该与测试有关,因为它是一个模拟对象,但它显然是在调用真实实例。
回到我的问题,当按下cmd + U时它是否还运行应用程序然后运行测试?
答案 0 :(得分:62)
应用程序实际上已运行,但您可以使用一种技巧来阻止它运行。
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;
}
答案 1 :(得分:20)
这是Sulthan使用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");
}
}
}
这将进入main.m,它应位于标准项目布局中的 Supporting Files 下。
然后在您的测试目录中添加:
<强> TestAppDelegate.h 强>
#import <Foundation/Foundation.h>
@interface TestAppDelegate : NSObject<UIApplicationDelegate>
@end
<强> TestAppDelegate.m 强>
#import "TestAppDelegate.h"
@implementation TestAppDelegate
@end
答案 2 :(得分:5)
如果您正在使用Swift(您可能没有main.c
),则必须执行以下步骤:
1:删除@UIApplicationMain
AppDelegate.swift
2:创建一个空的TestingAppDelegate.swift
import UIKit
class TestingAppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
}
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))
}
答案 3 :(得分:2)
答案 4 :(得分:1)
是的,您的测试目标将具有与应用目标的目标依赖关系,因此当您按Cmd + U或Cmd + Shift + U时,将构建应用目标。
答案 5 :(得分:1)
使用xCode 7和xCtool
xctool 能够在不运行应用程序的情况下执行单元测试。
要实现这一目标,
1。更新目标设置以在没有主机应用程序的情况下运行。
选择您的项目 - &gt;然后测试目标 - &gt;将主机应用程序设置为none。
<强> 2。如果没有,请安装xctool。
brew install xctool
第3。使用带xctool的终端运行测试。
xctool -workspace yourWorkspace.xcworkspace -scheme yourScheme run-tests -sdk iphonesimulator
答案 6 :(得分:1)
高于answers,建议在运行时动态更改应用程序委托。
我通过查询NSProcessInfo
进行的小修改是detect a unit test run。优点是您不需要检测可以检测单元测试是否正在运行的类。
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"
中的environmentDictionary
属性是单元测试包的路径,由Xcode设置。
答案 7 :(得分:0)
我使用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
....
}
答案 8 :(得分:0)