我如何从SenTestingKit / OCUnit迁移到XCTest?

我正在将我的项目从Xcode 4.6.3迁移到Xcode 5.0.2。 该项目的unit testing是用SenTestingKit / OCUnit开发的。 现在,当我在Xcode 5中运行testing时,从RunUnitTests脚本中得到一个错误,告诉我这一点

RunUnitTests已经过时。

Xcode 5发行说明中可能与此有关:

SenTestingKit和OCUnit已弃用。 使用移动器移动到XCTest。

不幸的是,我还没有find更多关于这个神秘的“移民”的信息。 可能我的google-fu缺乏[再次],所以我的主要问题是:如何将unit testing从SenTestingKit / OCUnit迁移到新的XCTest(带或不带“migrator”)?

第二个问题,如果迁移是一个复杂的业务:是否有可能让Xcode 5运行仍然基于SenTestingKit / OCUnit的unit testing? 毕竟这些只是被弃用,所以他们仍然应该在周围和function。

感谢Shaggy Frog的回答,我们知道Xcode发行说明中提到的神秘的“migrator”是通过select“Edit> Refactor> Convert To XCTest”启动的向导。 我将分两部分来介绍我与这位巫师的经历。 第一部分是对主要问题的不完全回答,第二部分回答第二个问题。


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

你首先需要意识到的是,为了向导工作,你需要select一个unit testing目标 。 如果select了主目标,向导将不会列出要转换的目标。

一旦我发现了这一点,我就可以通过巫师,但在我的情况下,最终的结果仍然是一个惊人的失败! 该向导声称,不需要更改源代码,只需要更新生成设置即可迁移到XCTest。 最后,向导甚至没有做到这一点:它确实删除了对SenTestingKit框架的引用,但没有引用XCTest框架。

无论如何,接下来是我必须手动进行的更改列表,因为向导未能为我做出这些更改。 如果这个向导更适合你,你可能不需要做所有这些事情。

  1. 从unit testing目标中删除“运行脚本”构build阶段
  2. 将所有testing用例类的基类从SenTestCaseXCTestCase
  3. 将导入的头从<SenTestingKit/SenTestingKit.h>更改为<XCTest/XCTest.h>
  4. 在testing目标的Build Settings中,将Wrapper扩展从octest改为xctest
  5. ST*所有断言macros重命名为XCT* (例如, STAssertTrue变成XCTAssertTrue
  6. 以上例外: STAssertEquals需要重新命名为XCTAssertEqual (注意最后缺less的“s”)。 你会知道,如果你得到这个编译器警告,你已经忘记了这一点: warning: implicit declaration of function 'XCTAssertEquals' is invalid in C99
  7. 新的XCTest声明macros不允许nil作为失败描述被传递。 例如, XCTAssertNotNil(anObject, nil)是不可能的,必须改为XCTAssertNotNil(anObject) 。 当你得到这个编译器错误时,你会知道你有这个问题: error: called object type 'NSString *' is not a function or function pointer
  8. 如果您确实需要传递失败描述,则新的XCTest声明macros需要格式说明符的常量expression式,就像NSString类方法stringWithFormat:所做的一样。 当你得到这个编译器错误时,你会知道你有这个问题: error: expected ')' 。 一些例子:
 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框架的引用添加到unit testing目标中。 如果遇到链接器错误,如Undefined symbols for architecture i386: "_OBJC_CLASS_$_XCTestCase", referenced from: foo您将会知道已经忘记了这一点。

Xcode 6更新 :在Xcode 6中不再需要与XCTest进行链接(事实上,XCTest甚至没有被列为可用的框架)。 而是将构build设置CLANG_ENABLE_MODULES设置为YES(在UI中显示为“启用模块(C和Objective-C)”)。 这会导致clang在看到#import <XCTest/XCTest.h>语句时自动与XCTest链接。 有关详细信息,请参见clang文档的“模块”部分 。


第2部分:如何在Xcode 5中运行OCUnittesting

在这一点上,我得到了一个链接器错误,让我意识到我的任务迁移到XCTest失败了。 原因是:XCTest不是SDK 6.1的一部分,但我仍然用基础SDK iOS 6.1构build我的项目( 这个答案解释了如何将SDK 6.1集成到Xcode 5中)。

由于我无法继续迁移,因此我目前的解决scheme是保留基于SenTestingKit / OCUnit的unit testing,直到find时间将我的应用升级到iOS 7。这就是我必须按顺序让unit testing运行:

  1. 从unit testing目标中删除“运行脚本”构build阶段。 这就是让Xcode在selectunit testing目标时通过“Test”操作( + U )执行unit testing所需的全部function。
  2. 不过这并不理想,因为我不想为了执行unit testing而切换目标。 相反,我想在select主要目标的同时执行unit testing。 因此,第二步是修改主目标的Xcodescheme,以便在运行“testing”操作时,执行unit testing目标的testing。

最终的解决scheme不如Xcode 4.x那样好,每次运行主目标的“运行”或“生成”操作时,unit testing都会自动执行。 不幸的是,如果没有“运行脚本”构build阶段,我似乎无法得到这个工作。

编辑 – >重构 – >转换为XCTest

OCUnittesting仍然可以工作,但你也可以迁移。 变化最终是相当小的。