tl;dr
Pivotal では、Ruby プロジェクトで Rspec を使用し、愛用しているため、Cedar を作成しました。Cedar は、OCUnit を置き換えたり競合したりすることを意図したものではありません。Rspec が Ruby で BDD スタイルのテストを開拓したように、Objective C に BDD スタイルのテストの可能性をもたらすことを意図していますが、Test::Unit を排除していません。どちらを選択するかは、主にスタイルの好みの問題です。
場合によっては、OCUnit が機能する方法のいくつかの欠点を克服するために Cedar を設計しました。具体的には、テストでデバッガーを使用して、コマンド ラインや CI ビルドからテストを実行し、テスト結果の有用なテキスト出力を取得できるようにしたいと考えていました。これらのことは多かれ少なかれ役に立つかもしれません。
長い答え
Cedar と OCUnit (たとえば) のような 2 つのテスト フレームワークの間で決定することは、2 つの点に帰着します: 好みのスタイルと使いやすさです。スタイルから始めましょう。これは単に意見と好みの問題だからです。使いやすさは、一連のトレードオフになる傾向があります。
スタイルに関する考慮事項は、使用するテクノロジーや言語を超えています。xUnit スタイルの単体テストは、BDD スタイルのテストよりもはるかに長い間使用されてきましたが、BDD スタイルのテストは、主に Rspec のおかげで急速に人気を博しています。
xUnit スタイルのテストの主な利点は、その単純さと、(単体テストを作成する開発者の間で) 広く採用されていることです。コードを書くと考えられるほぼすべての言語で、xUnit スタイルのフレームワークを使用できます。
xUnit スタイルと比較すると、BDD スタイルのフレームワークには、テスト (または仕様) の構造化方法と、アサーションを記述するための構文という 2 つの主な違いがある傾向があります。私にとっては、構造上の違いが主な差別化要因です。xUnit テストは 1 次元であり、特定のテスト クラスのすべてのテストに対して 1 つの setUp メソッドがあります。ただし、テストするクラスは 1 次元ではありません。多くの場合、競合する可能性のあるいくつかの異なるコンテキストでアクションをテストする必要があります。たとえば、 addItem: メソッドを持つ単純な ShoppingCart クラスを考えてみます (この回答では、Objective C 構文を使用します)。このメソッドの動作は、カートが空の場合と、カートに他のアイテムが含まれている場合とで異なる場合があります。ユーザーが割引コードを入力した場合は異なる場合があります。指定されたアイテムができない場合は異なる場合があります。選択した配送方法で発送されます。これらの可能な条件が互いに交差すると、可能なコンテキストの数が幾何学的に増加することになります。xUnit スタイルのテストでは、多くの場合、testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies のような名前のメソッドが多数発生します。BDD スタイルのフレームワークの構造により、これらの条件を個別に整理することができます。これにより、すべてのケースをカバーすることが容易になり、個々の条件の検索、変更、または追加が容易になります。例として、Cedar 構文を使用すると、上記のメソッドは次のようになります。xUnit スタイルのテストでは、多くの場合、testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies のような名前のメソッドが多数発生します。BDD スタイルのフレームワークの構造により、これらの条件を個別に整理することができます。これにより、すべてのケースをカバーすることが容易になり、個々の条件の検索、変更、または追加が容易になります。例として、Cedar 構文を使用すると、上記のメソッドは次のようになります。xUnit スタイルのテストでは、多くの場合、testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies のような名前のメソッドが多数発生します。BDD スタイルのフレームワークの構造により、これらの条件を個別に整理することができます。これにより、すべてのケースをカバーすることが容易になり、個々の条件の検索、変更、または追加が容易になります。例として、Cedar 構文を使用すると、上記のメソッドは次のようになります。
describe(@"ShoppingCart", ^{
describe(@"addItem:", ^{
describe(@"when the cart is empty", ^{
describe(@"with no discount code", ^{
describe(@"when the shipping method applies to the item", ^{
it(@"should add the item to the cart", ^{
...
});
it(@"should add the full price of the item to the overall price", ^{
...
});
});
describe(@"when the shipping method does not apply to the item", ^{
...
});
});
describe(@"with a discount code", ^{
...
});
});
describe(@"when the cart contains other items, ^{
...
});
});
});
場合によっては、共有のサンプル コンテキストを使用して DRY できる、同じ一連のアサーションを含むコンテキストが にあります。
BDD スタイルのフレームワークと xUnit スタイルのフレームワークの 2 番目の主な違いであるアサーション (または「マッチャー」) 構文は、仕様のスタイルをいくらか良くするだけです。本当に好きな人もいれば、そうでない人もいます。
それは使いやすさの問題につながります。この場合、各フレームワークには長所と短所があります。
OCUnit は Cedar よりもずっと前から存在しており、Xcode に直接統合されています。これは、新しいテスト ターゲットを作成するのが簡単であることを意味し、ほとんどの場合、テストを開始して実行することは「問題なく動作する」ことを意味します。一方で、iOS デバイスで実行する場合など、場合によっては OCUnit テストを機能させることがほぼ不可能であることがわかりました。Cedar 仕様のセットアップは、ライブラリを取得して自分でリンクしているため、OCUnit テストよりも多くの作業が必要です (Xcode では決して簡単な作業ではありません)。セットアップをより簡単にするために取り組んでおり、提案は大歓迎です。
OCUnit はビルドの一部としてテストを実行します。これは、テストを実行するために実行可能ファイルを実行する必要がないことを意味します。いずれかのテストが失敗すると、ビルドは失敗します。これにより、テストを実行するプロセスが 1 段階簡単になり、テスト出力がビルド出力ウィンドウに直接表示されるため、見やすくなります。いくつかの理由から、Cedar 仕様を個別に実行する実行可能ファイルに組み込むことにしました。
- デバッガーを使用できるようにしたかったのです。他の実行可能ファイルを実行するのと同じように Cedar 仕様を実行するため、同じ方法でデバッガーを使用できます。
- テストで簡単にコンソールにログインできるようにしたかったのです。OCUnit テストで NSLog() を使用できますが、出力はビルド ウィンドウに送られ、ビルド ステップを読み取るために展開する必要があります。
- コマンドラインと Xcode の両方で、読みやすいテスト レポートが必要でした。OCUnit の結果は Xcode のビルド ウィンドウにうまく表示されますが、コマンド ラインから (または CI プロセスの一部として) ビルドすると、テスト出力が他の多くのビルド出力と混ざり合ってしまいます。独立したビルド フェーズと実行フェーズにより、Cedar は出力を分離するため、テスト出力を簡単に見つけることができます。デフォルトの Cedar テスト ランナーは、標準の印刷スタイル "." をコピーします。Cedar にはカスタム レポーター オブジェクトを使用する機能もあるため、少しの努力で好きな方法で結果を出力させることができます。
OCUnit は、Objective C の公式の単体テスト フレームワークであり、Apple によってサポートされています。Apple は基本的に無限のリソースを持っているので、彼らが何かを成し遂げたいと思えば、それは成し遂げられるでしょう。そして、結局のところ、これは私たちがプレイしている Apple のサンドボックスです。しかし、その裏返しとして、Apple は毎日膨大な数のサポート リクエストとバグ レポートを受け取ります。彼らはそれらすべてを処理することについて非常に優れていますが、報告された問題をすぐに処理できないか、まったく処理できない場合があります. Cedar は OCUnit よりもはるかに新しく、未完成ですが、質問、問題、または提案がある場合は、Cedar メーリング リスト (cedar-discuss@googlegroups.com) にメッセージを送信してください。また、Github (github.com/pivotal/cedar) からコードを自由にフォークして、不足していると思われるものを追加してください。
iOS デバイスで OCUnit テストを実行するのは難しい場合があります。正直なところ、私はこれをかなり長い間試していなかったので、簡単になったかもしれませんが、最後に試したときは、UIKit 機能の OCUnit テストを動作させることができませんでした。Cedar を作成したとき、UIKit に依存するコードをシミュレーターとデバイスの両方でテストできるようにしました。
最後に、単体テスト用に Cedar を作成しました。これは、UISpec のようなプロジェクトと実際には比較できないことを意味します。UISpec を使用してからかなり時間が経ちましたが、主に iOS デバイスでプログラムによって UI を駆動することに重点が置かれていることがわかりました。Apple が (当時) UIAutomation を発表しようとしていたため、Cedar がこれらのタイプの仕様をサポートしないようにすることを明確に決定しました。