【问题标题】:Run logic tests in Xcode 4 without launching the simulator在 Xcode 4 中运行逻辑测试而不启动模拟器
【发布时间】:2011-11-08 15:17:14
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

    注意,未经 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
    

    之所以有效,是因为动态加载的组件(如测试包)中的方法类别优先。不过,Swizzling 感觉更安全。

    【讨论】:

    • 我应该把这段代码放在哪里?我当前的目标根本没有 AppDelegate。如果我将它添加到我的 UnitTest 目标中,它不会改变任何东西。 (我使用的是 XCode 4.6)
    • 你把它放在测试目标中,然后将MyAppDelegate 重命名为你的 AppDelegate 的类名在你的主要目标中。您的测试目标没有应用委托,但这就是这个问题的重点,来自主目标的应用委托仍然执行。
    【解决方案2】:

    请有人告诉我如何让测试工具不实例化整个应用程序?我的应用程序是事件驱动的,它在启动时会发送一堆事件,这会影响我的测试。

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

    【讨论】:

    • 我猜这仅适用于在 -application:didFinishLaunchingWithOptions: 中加载其 GUI 的应用程序。如果您正在构建一个使用故事板的应用程序怎么办?
    • 我应该把这段代码放在哪里?我当前的目标根本没有 AppDelegate。如果我将它添加到我的 UnitTest 目标中,它不会改变任何东西。 (我使用的是 XCode 4.6)
    • @VictorRonin 你有什么类型的目标没有应用程序委托?
    • @JonReid:好问题。我该如何检查?此目标没有摘要选项卡,当我查看 project.pbxproj 时,它看到 productType = "com.apple.product-type.bundle";对于这个目标。所以,我假设它构建了一个捆绑包。我需要什么类型的目标?
    • @JonReid:顺便说一句。如果您有工作样本,我将不胜感激,我可以从那里找出答案。
    【解决方案3】:

    使用 xCode 7 和 xctool

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

    为了让它工作,

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

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

    2。如果没有,请安装 xctool。

    brew install xctool
    

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

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

    【讨论】:

      【解决方案4】:

      在较早的答案中指出,对于这种情况,逻辑测试是正确的做法。我很难让逻辑测试与 XCode 版本 4.3.2 (4E2002) 一起工作。查看Apple's sample unit test project 帮助我理解了如何通过明确的分离来做到这一点。在该示例中,逻辑测试来自库目标的测试文件,而不是应用程序目标。该模型被封装到一个库中,然后与主目标和逻辑测试目标链接。应用程序目标仅包含视图和控制器。

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

      我可以想象这些说明有点令人困惑。如果你仔细分析上面提到的示例项目,你会得到一个更好的主意。

      【讨论】:

        【解决方案5】:

        在最新的 xcode 版本 (5.0.2) 中,您可以以非常简单的方式做到这一点。选择您的测试目标,“常规”选项卡。在“目标”字段中设置“无”。然后点击“构建阶段”选项卡并从“目标依赖项”中删除您的主要目标。

        【讨论】:

        • 你确定够了吗?我已经尝试了报告的步骤,但它仍然会启动模拟器。非常感谢
        • 要修复编译错误,请确保所有框架都链接到您的测试用例所需的框架(通常与您的 .app 链接到的相同)并确保您的构建阶段也编译您的测试用例所需的所有源文件.
        • 很好的答案!对于此解决方案不起作用的那些:请注意(至少使用 Xcode 7+),有两个测试目标:AppNameTests 和 AppNameUITests。在“Edit Schemes”->“Test”->“Info”中,这两个测试目标都启用了测试。在此处取消选择“UITests”。如果选择了“UITests”,这将有一个构建阶段来启动模拟器。
        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

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

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

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

          【讨论】:

            猜你喜欢
            • 2023-03-18
            • 1970-01-01
            • 2013-08-10
            • 2017-12-15
            • 1970-01-01
            • 1970-01-01
            • 2011-10-22
            • 2018-12-23
            • 1970-01-01
            相关资源
            最近更新 更多