如何从SenTestingKit / OCUnit迁移到XCTest?

时间:2013-11-16 19:06:30

标签: xcode5 ocunit xctest

我正在将项目从Xcode 4.6.3迁移到Xcode 5.0.2。该项目的单元测试是使用SenTestingKit / OCUnit开发的。现在,当我在Xcode 5中运行测试时,我从RunUnitTests脚本中收到错误告诉我

  

RunUnitTests已过时。

可能与Xcode 5发行说明中的​​注释相关:

  

不推荐使用SenTestingKit和OCUnit。使用迁移器移动到XCTest。

不幸的是,我无法找到更多关于这个神秘的“迁移者”的信息。可能我的google-fu缺乏[再次],所以我的主要问题是:如何将单元测试从SenTestingKit / OCUnit迁移到新的XCTest(有或没有“迁移器”)?

第二个问题,如果迁移是一项复杂的业务:是否有可能让Xcode 5运行仍基于SenTestingKit / OCUnit的单元测试?在所有这些仅仅被弃用之后,它们应该仍然存在并且功能正常。

2 个答案:

答案 0 :(得分:58)

感谢Shaggy Frog的回答,我们知道Xcode发行说明中提到的神秘“迁移器”是通过选择“编辑>重构>转换为XCTest”启动的向导。我将分两部分介绍我对这个向导的体验。第一部分是对主要问题的不完整答案,第二部分回答了次要问题。


第1部分:如何从OCUnit迁移到XCTest

您需要意识到的第一件事是,要使向导工作,您需要选择单元测试目标。如果选择了主目标,则向导不会列出要转换的任何目标。

一旦我发现了这一点,我就可以逐步完成向导,但就我而言,最终结果仍然是一次惊人的失败!该向导声称不需要进行任何源更改,只需要更新构建设置以迁移到XCTest。最后,向导甚至没有设法正确地执行此操作:删除对SenTestingKit框架的引用,但它确实引入了对XCTest的引用框架。

无论如何,接下来是我必须手动制作的更改列表,因为向导无法为我制作这些更改。如果向导更适合您,您可能不需要做所有这些事情。

  1. 从单元测试目标
  2. 中删除“运行脚本”构建阶段
  3. 将所有测试用例类的基类从SenTestCase更改为XCTestCase
  4. 将导入的标题从<SenTestingKit/SenTestingKit.h>更改为<XCTest/XCTest.h>
  5. 在测试目标的构建设置中,将包装器扩展名从octest更改为xctest
  6. 将所有断言宏从ST*重命名为XCT*(例如STAssertTrue变为XCTAssertTrue
  7. 上述例外情况:STAssertEquals需要重命名为XCTAssertEqual(注意最后缺少的“s”)。如果您收到此编译器警告,您将会忘记这一点:warning: implicit declaration of function 'XCTAssertEquals' is invalid in C99
  8. 新的XCTest断言宏不允许nil作为失败描述传递。例如,XCTAssertNotNil(anObject, nil)是不可能的,必须更改为XCTAssertNotNil(anObject)。当您收到此编译器错误时,您将知道存在此问题:error: called object type 'NSString *' is not a function or function pointer
  9. 如果你需要传递失败描述,那么新的XCTest断言宏需要格式说明符的常量表达式,就像NSString类方法stringWithFormat:那样。当您收到此编译器错误时,您将知道存在此问题:error: expected ')'。一些例子:
  10. NSString* formatSpecifier = @"%@";
    NSString* failureDescription = @"foo";
    // These are OK
    XCTAssertNotNil(anObject, @"foo")
    XCTAssertNotNil(anObject, @"%@", failureDescription)
    // These are not OK
    XCTAssertNotNil(anObject, failureDescription);
    XCTAssertNotNil(anObject, formatSpecifier, failureDescription);
    

    最后但并非最不重要的是,如前所述,需要将对XCTest框架的引用添加到单元测试目标中。如果您遇到Undefined symbols for architecture i386: "_OBJC_CLASS_$_XCTestCase", referenced from: foo等链接器错误,您就会知道已经忘记了这一点。

    Xcode 6更新:Xcode 6中不再需要与XCTest链接(实际上XCTest甚至不再列为可用框架)。而是将构建设置CLANG_ENABLE_MODULES设置为YES(在UI中显示为“启用模块(C和Objective-C)”)。这会导致clang在看到#import <XCTest/XCTest.h>语句时自动链接到XCTest。有关详情,请参阅"Modules" section of the clang documentation


    第2部分:如何在Xcode 5中运行OCUnit测试

    此时我收到一个链接器错误,让我意识到我迁移到XCTest的任务失败了。原因:XCTest不是SDK 6.1的一部分,但我仍然使用基础SDK iOS 6.1构建我的项目(this SO answer解释了如何将SDK 6.1集成到Xcode 5中)。

    由于我无法继续迁移,因此我目前的解决方案是基于SenTestingKit / OCUnit保持我的单元测试,直到我找到将我的应用程序升级到iOS 7的时间。这就是我所需要的为了让单元测试运行:

    1. 从单元测试目标中删除“运行脚本”构建阶段。这就是让Xcode在选择单元测试目标时通过“测试”操作( + U 执行单元测试所需的一切
    2. 但这并不理想,因为我不想仅仅为了执行单元测试而切换目标。相反,我想在选择主目标时执行单元测试 。因此,第二步是修改主目标的Xcode方案,以便在运行“测试”操作时,执行单元测试目标的测试。
    3. 最终的解决方案不如Xcode 4.x那样好,每当我运行主目标的“运行”或“构建”动作时,单位测试就会自动执行。不幸的是,似乎在没有“运行脚本”构建阶段的情况下我无法工作。

答案 1 :(得分:14)

编辑 - &gt;重构 - &gt;转换为XCTest

OCUnit测试仍然有效,但您也可以迁移。这些变化最终很小。