我想在不启动模拟器的情况下使用OCUnit在Xcode 4中运行测试。请不要试图说服我,我正在做单元测试错误或类似的事情。我喜欢以传统的方式进行TDD:在测试中为类编写API,然后让类通过测试。我将编写单独的测试,这些测试是在模拟器中运行的端到端测试。在没有启动模拟器的情况下在Xcode 4中运行逻辑测试
如果没有办法做到这一点,那么请有人告诉我如何让测试工具不实例化整个应用程序?我的应用程序是事件驱动的,当它启动时,我的测试混乱了,它发送了一堆事件。
我想在不启动模拟器的情况下使用OCUnit在Xcode 4中运行测试。请不要试图说服我,我正在做单元测试错误或类似的事情。我喜欢以传统的方式进行TDD:在测试中为类编写API,然后让类通过测试。我将编写单独的测试,这些测试是在模拟器中运行的端到端测试。在没有启动模拟器的情况下在Xcode 4中运行逻辑测试
如果没有办法做到这一点,那么请有人告诉我如何让测试工具不实例化整个应用程序?我的应用程序是事件驱动的,当它启动时,我的测试混乱了,它发送了一堆事件。
在你的情况,我假设你有一个单独的逻辑测试和应用程序测试目标(如果没有 - 你需要)。在您的方案配置中,您可以定义为“测试”方案构建的目标。如果您的应用程序测试没有运行,模拟器将不会启动。
我怀疑你可能试图在“应用程序测试”目标(例如Xcode默认创建的目标)中运行'逻辑测试'。查看更多关于这个区别here(以及如何设置)。
我用GHUnit来创建兼容osx/ios的测试套件。有几个问题,但我发现它比OCUnit更可靠/兼容/直接。
GHUnit为OS X和iOS提供了基本的模板项目,使初始设置变得简单。
注:我通常只使用我自己的套件进行大多数测试。
请有人能告诉我如何让测试工具不实例化整个应用程序?我的应用程序是事件驱动的,当它启动时,我的测试混乱了,它发送了一堆事件。
我使用Xcode 4的内置测试。应用程序实例化可能看起来很痛苦,但是当我在Xcode Unit Testing: The Good, the Bad, the Ugly上编写时,它可以在不区分逻辑测试和应用程序测试的情况下编写测试。具体来说,它允许我为视图控制器编写单元测试。
这就是我做,以避免我的全部启动顺序:
编辑方案
runningTests
设置为YES
编辑应用程序委托
以下内容添加到-application:didFinishLaunchingWithOptions:
只要是有意义的:
#if DEBUG
if (getenv("runningTests"))
return YES;
#endif
执行相同的-applicationDidBecomeActive:
而只是return
。
更新:我改变了我的方法。请参阅How to Easily Switch Your App Delegate for Testing。
在之前的回答中指出,逻辑测试对于这种情况是正确的。我在使用XCode 4.3.2(4E2002)进行逻辑测试方面非常艰难。看着Apple's sample unit test project帮助我理解了如何以明确的分离方式做到这一点。在那个例子中,逻辑测试来自库目标的测试文件,而不是应用程序目标。该模型被封装成一个库,然后与主要目标和逻辑测试目标链接。应用程序目标仅包含视图和控制器。
基于这种模式,这是我做了让我的逻辑测试正常工作。创建一个新的目标(Cocoa Touch静态库),并将所有文件移动到这个新目标进行逻辑测试(通常是所有模型)。 “Build Phases”设置在“Link Binary With Libraries”您的应用程序目标和逻辑测试目标中添加此新库。
我可以想象这些说明有点混乱。如果你剖析上面提到的示例项目,你会得到一个更好的主意。
注意,在Xcode的5
未经测试我使用@乔恩 - 里德的答案时,却发现Xcode中加环境变量XcodeProjects的xcuserstated部分,而这些用户特定的,而不是通常承诺存储库。因此,我调酒我的AppDelegate覆盖其装载:
@implementation MyAppDelegate (Testing)
+ (void)initialize {
SEL new = @selector(application:didFinishLaunchingWithOptions:);
SEL orig = @selector(swizzled_application:didFinishLaunchingWithOptions:);
Class c = [self class];
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
} else {
method_exchangeImplementations(origMethod, newMethod);
}
}
- (BOOL)swizzled_application:(id)app didFinishLaunchingWithOptions:(id)opts {
return YES;
}
@end
注意的是,以下是简单的和仍然有效,但我不知道它是可靠的:
@implementation MyAppDelegate (Testing)
- (BOOL)application:(id)app didFinishLaunchingWithOptions:(id)opts {
return YES;
}
@end
这工作,因为类别动态加载组件中的方法(如测试包)优先。虽然Swizzling感觉更安全。
我应该在哪里放置这段代码?我目前的目标根本没有AppDelegate。如果我将它添加到我的UnitTest目标中,它不会改变任何内容。 (我正在使用XCode 4.6) –
你把它放在测试目标中,并且你将'MyAppDelegate'重命名为你的AppDelegate的类名在你的主目标中。您的测试目标没有应用程序委托,但这就是这个问题的要点,来自主目标的应用程序委托*仍然*执行。 – mxcl
在Xcode 5中不起作用xcunit测试 – user170317
感谢您的提示!使用和完美的工作。 – yonel
我想这只适用于加载他们的GUI在应用程序:didFinishLaunchingWithOptions:的应用程序。如果您正在构建使用故事板的应用程序,该怎么办? – ABeanSits
我应该在哪里放这段代码?我目前的目标根本没有AppDelegate。如果我将它添加到我的UnitTest目标中,它不会改变任何内容。 (我正在使用XCode 4.6) –