在不启动模拟器的情况下在Xcode 4中运行逻辑测试

时间:2011-09-01 18:24:06

标签: objective-c xcode tdd ios-simulator ocunit

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

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

7 个答案:

答案 0 :(得分: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

答案 1 :(得分:5)

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

答案 2 :(得分:3)

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

我怀疑您可能正在尝试在“应用程序测试”目标中运行“逻辑测试”(例如Xcode默认创建的目标)。详细了解这种差异here(以及如何设置)。

答案 3 :(得分:2)

在之前的回答中指出,逻辑测试对于这种情况来说是正确的。我在使用XCode版本4.3.2(4E2002)进行逻辑测试时非常困难。看Apple's sample unit test project让我明白如何通过明确的分离来做到这一点。在该示例中,逻辑测试来自库目标的测试文件,而不是应用程序目标。该模型被封装到一个库中,然后与主目标和逻辑测试目标链接。应用程序目标仅包含视图和控制器。

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

我可以想象这些说明有点令人困惑。如果您剖析上面提到的示例项目,您将会有更好的想法。

答案 4 :(得分:2)

注意,在Xcode 5上未经测试。

我使用@jon-reid’s answer,但发现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

这是有效的,因为动态加载的组件(如测试包)中的方法类别优先。但是,调侃感觉更安全。

答案 5 :(得分:1)

使用xCode 7和xctool

xctool 能够在没有模拟器的情况下执行单元测试。

要实现这一目标,

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

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

enter image description here

<强> 2。安装xctool,如果你没有。

brew install xctool

第3。使用带xctool的终端运行测试。

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

答案 6 :(得分:0)

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

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

注意:我通常只使用自己的套件进行大部分测试。