Building Testable Windows Phone Applications from Patterns & Practices-(2)

皆様、こんにちは!

さて今回は、P & P ライブラリから、 Windows Phone テスト駆動アプリケーションの構築 、をご紹介しましょう。今回は後半部分のご紹介に参ります。

Windows Phone アプリケーションの単体テスト

単体テストは、その中で可能な機能の最小単位をテストする統合テストまたはユーザー受け入れテストとは異なります。通常、単体テストは、特定のメソッドの動作をテストします。下記の表は、単体テストと統合テストを比較したものです。

単体テスト

統合テスト

依存システムは必要なし

依存システムが必要で、かつオンラインである必要

高速に実行できる

実行に時間がかかる

通常は頻繁に (開発とコードのチェックイン中に) 実行

通常、定期的に実行

開発者の期待をテストする 実際のシステムの動作をテストする

統合テストと比較した場合の単体テストの最も重要な側面は、単体テストは、テストされるコードを実行するためには、依存のシステムの機能に依存する必要がないことです。もしテストされているメソッドがIsolatedStorageException などのエラーを吐き出した場合に、例えばコード パスをトリガーするために分離ストレージを破損することは、必ずしも最適ではありません。同様に、サービスまたはクエリのデータベースを呼び出すコードをテスト依存のシステムに依存しないようにします。もしそのテストが依存システムが正しく設定され、実行され、既知のデータで充足されることを必要とする場合には、そのテストは非常に壊れやすいだろうし、これらの条件のいずれかが満たされない場合には失敗してしまうでしょう。このような状況で、多くの失敗するテスト は、テスト対象コードの問題ではなく、依存のシステムの問題のために起こります。

ソフトウェア テストの容易性を高めるための適切なアプローチは、依存システムを分離し、抽象インターフェイスまたは抽象クラスなどを使用して、ビジネス ロジックに渡されることです。このアプローチにより、ビジネス ロジックが実行時に渡され、依存システムのテストをパスさせることができます。さらに、テストの容易性の面では、それも、依存システムのモックアップバージョンのテストも実施できます。詳細は、Martin FowlerのWebサイトにあるForms of Dependency Injectionを参照してください。

単体テストは、どのようにしてテスト対象のコードが動作するべきかに関する、コードベースのドキュメントとして考えることができます。もし当該テスト対象コードがリファクタリングまたは再編成される場合でも、機能は同じままである必要があり、単体テスは同じくパスする必要があります。もし単体テストに合格しない場合は、それはコードの不適切なリファクタリングによる可能性があります。別の可能性としては、単体テストの更新には、望ましいコードの動作が変更されており、その場合には、単体テスト自体が更新されるか、新しいテストを追加する必要があります。

Windows Phone 7.1 SDK クラスの抽象化

いくつかのパブリックインターフェイスまたは抽象クラスは、Windows Phone 7.1 SDK で利用可能です。それゆえ、インターフェイスは、付属のサンプルアプリケーションで使用される Windows Phone 7.1 SDK 内のクラスのいくつかために生成されました。当該インターフェイスは、Doubler という名前の Reflector アドインを使用して生成されました。Doubler はコードジェネレータで、これにより、一つのアセンブリの中の選択されたタイプのためのラッパークラスとそのインターフェースを生成できます。

アダプターとファサード、は生成されたインターフェイスを実装するラッパークラスであり、同じように生成されます。アダプタークラスは、基になる Windows Phone 7.1 SDK クラスにパラメーターを渡し、値を返します。当該アダプターは、そのインターフェイスへの呼び出しを、元のインターフェイスへの呼び出しに変換します。ファサードクラスが提供するのは、一つのクラスへの簡素化されたインターフェイスで、そのインターフェイスへの呼び出しを、元のクラスへの呼び出しに翻訳するクラスを提供します。アダプターとファサードを作成することにより、疎結合テストしやすいコードを記述することができます。

アダプターは、一つのクラスのための一つのインターフェイスを一つの互換性のあるインターフェイスに変換するデザインパターンです。当該アダプターは、そのインターフェイスへの呼び出しを、元のインターフェイスへの呼び出しに変換します。ファサードは、一つのクラスのためにシンプルなインターフェイスを提供するデザインパターンです。ファサードば、そのインタフェースへの呼び出しを、元のクラスへの呼び出しに変換します。これら両方のアプローチにより、疎結合テストしやすいコードを記述する事ができるようになります。

次の図に示す方法は、どのようにして GeoCoordinateWatcherAdapter クラスが GeoCoordinateWatcher SDK クラスを適用するかを示しています。

Hh830877.7E8E13056F6D007B92C639C52527F176(en-us,PandP.10).png

GeoCoordinateWatcherAdapter クラスは、IGeoCoordinateWatcher インターフェイスを実装します。GeoCoordinateWatcher クラスを使用するすべてのクラスの中で場所を取得するには、このクラスの代わりに、GeoCoordinateWatcherAdapter クラスを代わりに使用する必要があります。

図の右側はMockGeoCoordinateWatcher クラスを示しており、このクラスはIGeoCoordinateWatcher インターフェイスを実装し、単体テストにおいては GeoCoordinateWatcher の代わりに GeoCoordinateWatcherAdapter クラスを使用します。このクラスは、GeoCoordinateWatcher クラスと対話する必要があるビジネス ロジックの単体テストを行う機能を提供します。

次に示すラッパークラス群が提供されており、これらは、 Microsoft.Practices.Phone.Adapters プロジェクトで見つけることができます。

Wrapper Implements Abstracted Class
AccelerometerAdapter IAccelerometer Accelerometer
ApplicationFrameNavigationService INavigationService PhoneApplicationFrame
CameraCaptureTaskAdapter ICameraCaptureTask CameraCaptureTask
CompassAdapter ICompass Compass
GeoCordinateWatcherAdapter GeoCoordinateWatcher, IGeoCoordinateWatcher GeoCoordinateWatcher
GyroscopeAdapter IGyroscope Gyroscope
IsolatedStorageFacade IIsolatedStorageFacade IsolatedStorageFileAdapter, IsolatedStorageFileStreamAdapter
IsolatedStorageFileAdapter IIsolatedStorageFile IsolatedStorageFile
IsolatedStorageFileStreamAdapter IsolatedStorageFileStream, IIsolatedStorageFileStream IsolatedStorageFileStream
MessageBoxAdapter IMessageBox MessageBox
MotionAdapter IMotion Motion
AccelerometerSensorReading ISensorReading AccelerometerReading
CompassSensorReading ISensorReading CompassReading
GyroscopeSensorReading ISensorReading GyroscopeReading
MotionSensorReading ISensorReading MotionReading
PhotoResultTaskEventArgs TaskEventArgs PhotoResult

Mock の実装

単体テストがフォーカスすべきは、テスト対象コードが依存システムによって返される値への応答です。Mock を使用することにより、戻り値または依存システムのモックのインスタンスによってスローされる例外を、簡単に制御できます。詳細は、MSDN マガジンの Exploring the Continuum of Test Doubles  を参照してみてください。

Microsoft.Practices.Phone.Testing プロジェクトには Windows Phone 7.1 SDK アダプターと、Microsoft.Practices.Phone.Adapters プロジェクトに含まれるファサード クラスの Mock の実装が含まれています。これらの Mock の使用用途は一般的なもので、デリゲートを受け入れるプロパティを持つ多くのメソッドを使って開発されました。デリゲートを受け入れるプロパティは、単体テストに必要な動作の実行を有効にします。

単体テストの実行

このテストのプロジェクは Windows Phone と Silverlight 4 のための Silverlight Unit Testing Framework を使用しています。テストを実行するには、最初にビルドして、次にプロジェクト をWindows Phone 実機かWindows Phone エミュレーターに配置します。Windows Phone 実機上では、例えば、TestableGPSSample.Tests、といった名前のアプリケーションが起動でき、そして実行したい単体テストを選択できます。

Silverlight Unit Testing Framework は、単体テストを実行するために、Windows Phone 実機およびエミュレータの両方で使用されます。

以上です。いかがでしょうか?

次の次位からは、いよいよお待たせしているWDDのセッション解説第2弾かな(^^;)?こちらもお楽しみに。

鈴木 章太郎