web-dev-qa-db-ja.com

SenTestingKit / OCUnitからXCTestに移行するにはどうすればよいですか?

Xcode 4.6.3からXcode 5.0.2にプロジェクトを移行中です。プロジェクトのユニットテストは、SenTestingKit/OCUnitを使用して開発されました。 Xcode 5でテストを実行しているときに、RunUnitTestsスクリプトからエラーが表示され、

RunUnitTestsは廃止されました。

おそらく関連しているのは、Xcode 5リリースノートのこのノートです。

SenTestingKitとOCUnitは非推奨です。 Migratorを使用してXCTestに移動します。

残念ながら、私はこの神秘的な「移住者」についてこれ以上知ることができませんでした。おそらく私のgoogle-fuに[再び]がないため、主な質問は次のとおりです。ユニットテストをSenTestingKit/OCUnitから新しいXCTestに移行するにはどうすればよいですか( "migrator"の有無にかかわらず)?

移行が複雑なビジネスの場合の2番目の質問:Xcode 5に、まだSenTestingKit/OCUnitに基づいた単体テストを実行させることは可能ですか?結局のところ、これらは単に非推奨になっているだけなので、まだ機能しているはずです。

35
herzbube

シャギーフロッグの回答のおかげで、Xcodeのリリースノートに記載されている謎の「移行者」は、「編集」>「リファクタリング」>「XCTestに変換」を選択して起動されるウィザードであることがわかります。このウィザードを使用した経験について、2つのパートで説明します。最初の部分は一次質問に対する不完全な回答であり、2番目の部分は二次質問に対する回答です。


パート1:OCUnitからXCTestに移行する方法

最初に理解する必要があるのは、ウィザードを機能させるために、ユニットテストのターゲットを選択する必要があるということです。メインターゲットが選択されている場合、ウィザードは変換するターゲットをリストしません。

このことを知った後は、ウィザードをステップスルーすることができましたが、私の場合、最終的な結果はまだ壮観な失敗でした!ウィザードは、ソースの変更は不要であり、XCTestに移行するために更新する必要があるのはビルド設定のみであると主張しました。結局、ウィザードはそれを正しく行うことさえできませんでした:それはdidSenTestingKitフレームワークへの参照を削除しましたが、しませんでしたXCTestフレームワークへの参照を入れます。

とにかく、次のリストは、ウィザードが私に代わって作成できなかったために手動で加えなければならない変更のリストです。ウィザードがうまく機能する場合は、これらのすべてを実行する必要がない場合があります。

  1. ユニットテストターゲットから「スクリプトの実行」ビルドフェーズを削除する
  2. すべてのテストケースクラスの基本クラスをSenTestCaseからXCTestCaseに変更します
  3. インポートされたヘッダーを<SenTestingKit/SenTestingKit.h>から<XCTest/XCTest.h>に変更します。
  4. テストターゲットのビルド設定で、ラッパー拡張機能をoctestからxctestに変更します。
  5. すべてのアサートマクロの名前をST*からXCT*に変更します(例:STAssertTrueXCTAssertTrueになります)
  6. 上記の例外:STAssertEqualsXCTAssertEqualに名前を変更する必要があります(末尾の「s」がないことに注意してください)。次のコンパイラ警告が表示された場合は、このことを忘れていることがわかります:warning: implicit declaration of function 'XCTAssertEquals' is invalid in C99
  7. 新しいXCTestアサートマクロでは、nilを失敗の説明として渡すことができません。たとえば、XCTAssertNotNil(anObject, nil)は使用できないため、XCTAssertNotNil(anObject)に変更する必要があります。このコンパイラエラーが発生すると、この問題があることがわかります:error: called object type 'NSString *' is not a function or function pointer
  8. doが失敗の説明を渡す必要がある場合、NSStringクラスメソッドstringWithFormat:と同じように、新しいXCTestアサートマクロはフォーマット指定子の定数式を必要とします。このコンパイラエラーが発生すると、この問題があることがわかります: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フレームワークへの参照を単体テストターゲットに追加する必要があります。 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に自動的にリンクします。詳細は clangドキュメンテーションの「モジュール」セクション にあります。


パート2:Xcode 5でOCUnitテストを実行する方法

この時点で、XCTestに移行するという私の使命が失敗したことに気付かせるリンカエラーが発生しました。理由:XCTestはSDK 6.1の一部ではありませんが、ベースSDK iOS 6.1( this SO answer はSDK 6.1をXcode 5)。

移行を続行できないため、現時点での私の解決策は、アプリをiOS 7にアップグレードする時間が見つかるまで、SenTestingKit/OCUnitに基づいてユニットテストを維持することです。これは、私がしなければならなかったことです。ユニットテストを実行させるには:

  1. ユニットテストターゲットから「スクリプトの実行」ビルドフェーズを削除します。 Xcodeが「テスト」アクションを介して単体テストを実行するために必要なのはこれだけです( + Uユニットテストターゲットが選択されている間
  2. ただし、単体テストを実行するためだけにターゲットを切り替えたくないので、これは理想的ではありません。代わりに、メインターゲットが選択されている間にユニットテストを実行したい。したがって、2番目の手順は、メインターゲットのXcodeスキームを変更して、「テスト」アクションを実行すると、代わりに単体テストターゲットのテストが実行されるようにすることです。

最終的な解決策は、メインターゲットの「実行」または「ビルド」アクションを実行するたびにユニットテストが自動的に実行されるXcode 4.xほど良くありません。残念ながら、「スクリプトの実行」ビルドフェーズなしでは、これを機能させることはできないようです。

59
herzbube

編集->リファクタリング-> XCTestに変換

OCUnitテストは引き続き機能しますが、移行することもできます。変更は最終的にはごくわずかです。

14
Shaggy Frog