2011-09-01 107 views
28

我想在不启动模拟器的情况下使用OCUnit在Xcode 4中运行测试。请不要试图说服我,我正在做单元测试错误或类似的事情。我喜欢以传统的方式进行TDD:在测试中为类编写API,然后让类通过测试。我将编写单独的测试,这些测试是在模拟器中运行的端到端测试。在没有启动模拟器的情况下在Xcode 4中运行逻辑测试

如果没有办法做到这一点,那么请有人告诉我如何让测试工具不实例化整个应用程序?我的应用程序是事件驱动的,当它启动时,我的测试混乱了,它发送了一堆事件。

回答

3

在你的情况,我假设你有一个单独的逻辑测试和应用程序测试目标(如果没有 - 你需要)。在您的方案配置中,您可以定义为“测试”方案构建的目标。如果您的应用程序测试没有运行,模拟器将不会启动。

我怀疑你可能试图在“应用程序测试”目标(例如Xcode默认创建的目标)中运行'逻辑测试'。查看更多关于这个区别here(以及如何设置)。

0

我用GHUnit来创建兼容osx/ios的测试套件。有几个问题,但我发现它比OCUnit更可靠/兼容/直接。

GHUnit为OS X和iOS提供了基本的模板项目,使初始设置变得简单。

注:我通常只使用我自己的套件进行大多数测试。

28

请有人能告诉我如何让测试工具不实例化整个应用程序?我的应用程序是事件驱动的,当它启动时,我的测试混乱了,它发送了一堆事件。

我使用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

+0

感谢您的提示!使用和完美的工作。 – yonel

+1

我想这只适用于加载他们的GUI在应用程序:didFinishLaunchingWithOptions:的应用程序。如果您正在构建使用故事板的应用程序,该怎么办? – ABeanSits

+0

我应该在哪里放这段代码?我目前的目标根本没有AppDelegate。如果我将它添加到我的UnitTest目标中,它不会改变任何内容。 (我正在使用XCode 4.6) –

2

在之前的回答中指出,逻辑测试对于这种情况是正确的。我在使用XCode 4.3.2(4E2002)进行逻辑测试方面非常艰难。看着Apple's sample unit test project帮助我理解了如何以明确的分离方式做到这一点。在那个例子中,逻辑测试来自库目标的测试文件,而不是应用程序目标。该模型被封装成一个库,然后与主要目标和逻辑测试目标链接。应用程序目标仅包含视图和控制器。

基于这种模式,这是我做了让我的逻辑测试正常工作。创建一个新的目标(Cocoa Touch静态库),并将所有文件移动到这个新目标进行逻辑测试(通常是所有模型)。 “Build Phases”设置在“Link Binary With Libraries”您的应用程序目标和逻辑测试目标中添加此新库。

我可以想象这些说明有点混乱。如果你剖析上面提到的示例项目,你会得到一个更好的主意。

2

注意,在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感觉更安全。

+0

我应该在哪里放置这段代码?我目前的目标根本没有AppDelegate。如果我将它添加到我的UnitTest目标中,它不会改变任何内容。 (我正在使用XCode 4.6) –

+0

你把它放在测试目标中,并且你将'MyAppDelegate'重命名为你的AppDelegate的类名在你的主目标中。您的测试目标没有应用程序委托,但这就是这个问题的要点,来自主目标的应用程序委托*仍然*执行。 – mxcl

+1

在Xcode 5中不起作用xcunit测试 – user170317

5

在上一个xcode版本(5.0.2)中,您可以非常简单地完成此操作。选择你的测试目标,“常规”选项卡。在“目标”栏中设置“无”。然后点击“构建阶段”标签并从“目标依赖项”中移除主目标。

+2

你确定够了吗?我试过报告的步骤,但它仍然启动模拟器。非常感谢 –

+0

我尝试这个,但得到编译错误。 – jolestar

+0

要修复编译错误,请确保所有框架都链接到测试用例需要的位置(通常与.app链接的位置相同),并确保构建阶段也编译测试用例所需的所有源文件。 – mxcl

0

使用XCODE 7和xctool

xctool能够执行单元测试而不模拟器。

得到这个工作,

1。更新没有主机应用程序的目标设置。

选择您的项目 - >然后测试目标 - >将主机应用程序设置为无。

enter image description here

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

brew install xctool 

3.执行使用终端与xctool测试。

xctool -workspace yourWorkspace.xcworkspace -scheme yourScheme run-tests -sdk iphonesimulator 
相关问题