web-dev-qa-db-ja.com

単体テストとプライベート変数

パブリックメソッドのBDD単体テストを書いています。メソッドはプライベートプロパティを変更します(private var)したがって、expect()を記述し、それが正しく設定されていることを確認したいと思います。プライベートなので、単体テストのターゲットからどのようにアクセスするのかわかりません。

Objective-Cの場合、拡張ヘッダーを追加するだけです。 Swiftに同様のトリックはありますか?注として、プロパティにはいくつかのコードとともにdidSet()もあります。

36

(Swift 2は@testable属性を追加します。これにより、内部メソッドとプロパティをテストに使用できます。詳細については、以下の@JeremyPのコメントを参照してください。)

いいえ。Swiftでは、privateはprivateです。コンパイラはこの事実を使用して最適化できるため、そのプロパティの使用方法に応じて、コンパイラがそれを削除、インライン化、または実際にそのコードに基づいて正しい動作を与える他のことを行うことは正当ですファイル。 (オプティマイザーが実際に今日スマートであるかどうかに関係なく、オプティマイザーは許可されています。)

もちろん、クラスを@objcと宣言すると、それらの最適化を破ることができ、ObjCをいじって読むことができます。また、Swift=を使用して任意の@objc公開メソッド(ゼロタイムアウトNSTimerなど)を呼び出すことができる奇妙な回避策があります。 。

これは古典的なテストの問題であり、古典的なテストの答えはこのようにテストしないことです。内部状態をテストしないでください。何かが起こったことを外部から伝えることが文字通り不可能な場合、テストするものはありません。オブジェクトを再設計して、パブリックインターフェイスでテストできるようにします。通常、それは構成とモックを意味します。

おそらく、この問題の最も一般的なバージョンはキャッシングです。何かが実際にキャッシュされているかどうかをテストするのは非常に困難です。唯一の違いは、それがより速く取得されることです。しかし、それはまだテスト可能です。キャッシング機能を別のオブジェクトに移動し、テスト対象オブジェクトにカスタムキャッシングオブジェクトを受け入れさせます。次に、正しいキャッシュ呼び出し(またはネットワーク呼び出し、データベース呼び出し、または内部状態が保持するもの)が行われたかどうかを記録するモックを渡すことができます。

基本的な答えは、テストしやすいように再設計することです。

わかりましたが、あなたは本当に、本当に、本当にそれを必要とします...それをする方法? OK、世界を壊すことなく可能です。

テストするファイル内に、必要なものを公開する関数を作成します。メソッドではありません。ただの無料機能。次に、そのヘルパー関数を#if TESTに配置し、テスト構成でTESTを設定できます。理想的には、変数を公開するのではなく、関数が実際にあなたが関心のあることをテストするようにします(その場合は、関数を内部またはパブリックにすることもできます)。しかし、どちらにしても。

47
Rob Napier