web-dev-qa-db-ja.com

Xcodeでのプラ​​イベートメソッドの単体テスト

私はおもちゃプロジェクトでテスト駆動開発を試みています。クラスのパブリックインターフェイスでテストを機能させることができます(ただし、テストされているメソッドよりも多くのテストコードを記述しているため、まだフェンスの中にいます)。

私は、パブリックインターフェイスをクリーンに保つために、多くのプライベートメソッドを使用する傾向があります。ただし、これらのメソッドのテストは引き続き使用したいと思います。

Cocoaは動的言語であるため、これらのプライベートメソッドを呼び出すことはできますが、テストで、クラスがこれらのメソッドに応答しない可能性があるという警告が表示されます(ただし、明らかに応答します)。警告なしでコンパイルしたいので、ここに私の質問があります:

  1. Xcodeでこれらの警告をオフにするにはどうすればよいですか?
  2. これらの警告をオフにするために他に何かできることはありますか?
  3. 「ホワイトボックス」テストを試す際に何か問題がありますか?
63
Abizern

Xcodeでこれらの警告をオフにするにはどうすればよいですか?

しないでください。

これらの警告をオフにするために他に何かできることはありますか?

しないでください。

「ホワイトボックス」テストを試す際に何か問題がありますか?

番号。

解決策は、プライベートメソッドを独自のヘッダーのカテゴリに移動することです。このヘッダーを実際のクラスとテストケースクラスの両方の実装ファイルにインポートします。

89
Peter Hosey

Objective-Cには「プライベートメソッド」のようなものは実際には存在しないこと、そしてそれが動的言語であるというだけではないことを忘れないでください。仕様上、Objective-Cにはivarの可視性修飾子がありますが、メソッドにはありません。好きなメソッドを呼び出すことができるのは偶然ではありません。

@ Peterの提案は素晴らしいものです。彼の答えを補足するために、私が使用した代替方法(プライベートメソッドにのみヘッダーが必要でない/必要がない場合)は、ユニットテストファイル自体でカテゴリを宣言することです。 (名前として@interface MyClass (Test)を使用します。)これは、テスト対象のクラスがアクセスするivarにアクセスする場合など、リリースコードで不必要な膨張を伴うメソッドを追加するための優れた方法です。 (プロパティを使用する場合、これは明らかに問題の少ないものです。)

このアプローチにより、内部状態の公開と検証、およびテスト専用メソッドの追加が簡単になることがわかりました。たとえば、 この単体テストファイル では、-isValidバイナリヒープの正当性を検証するためのメソッド。本番環境では、ヒープが有効であると想定しているので、この方法はスペースの無駄になります。コードを変更する場合、ユニットテストの回帰をテストするときにのみ、この方法に注意します。

125
Quinn Taylor

別の質問に答えがあるようです: Xcodeで警告を抑制する方法はありますか?

4
Andrew Burns

プライベートヘッダーを使用するか、独自のカテゴリを定義する方がおそらくより正しいソリューションですが、メソッドを呼び出す前にオブジェクトを(id)にキャストするという非常に単純な別のソリューションもあります。

3
Jon Steinmetz

数日前にTDDを始めたとき、私は同じ問題を扱っていました。 Test-Driven iOS Development の本でこの非常に興味深い視点を見つけました:

「プライベートメソッドをテストする必要がありますか?」または関連する質問「プライベートメソッドをどのようにテストすればよいですか?」 2番目の質問をする人々は、最初の質問に対する答えが「はい」であると想定しており、現在、テストスイートでクラスのプライベートインターフェイスを公開する方法を探しています。

私の答えは、微妙な事実の観察に依存しています。あなたはすでにプライベートメソッドをテストしました。テスト駆動開発で一般的な赤、緑、リファクタリングのアプローチに従って、オブジェクトのパブリックAPIを設計して、それらのオブジェクトが実行する必要がある作業を実行しました。テストで指定された作業、および何も壊していないことを保証するテストの継続的な実行により、必要に応じてクラスの内部配管を自由に編成できます。

実行しているのは、すでにテスト済みの動作をリファクタリングするだけなので、プライベートメソッドはすでにテストされています。プライベートメソッドは、パブリックメソッドの実装をクリーンアップする機会がある場合にのみ作成されるため、テストされていない、またはテストが不完全な状況になることはありません。これにより、プライベートメソッドは確実にパブリックメソッドから呼び出されるため、テスト中に呼び出す必要があるクラスをサポートするためだけにプライベートメソッドが存在することが保証されます。

3
Alois Holub

プライベートメソッドの実装を複数のソースファイルに分散させたくない場合、カテゴリソリューションの改良点は、ヘッダーファイルで拡張機能(基本的には匿名のカテゴリ- Appleのドキュメントを参照 を参照)を定義することです。これは、既存のクラスの実装と関連する単体テストのソースファイルの両方によってインポートされます。

拡張機能を使用すると、プライベートメソッドの実装がメインの@implementationブロックに存在しない場合にコンパイラーが警告を出すことができます。 このリンク はそれをうまく説明しています。

3
user2067021

簡単な仕事。手順:1.-(NSString *)getTestStringがあります。インターフェースFooのターゲットmファイル

  1. 単体テストファイルにカテゴリを追加します。

    @interface DemoHomeViewController()-(NSString *)getTestString; @終わり

次に、今したいことをすべて実行します。

1
Henry Sou