ホーム > コンピュータ > C# > WPF in C# > Prism

ベクトルドロー・レベルゼロ+

Prism Library 5.0 for WPFを使用する高度なMVVMの筋書き 07[C# WPF Prism]

新規作成日 2015-10-15
最終更新日

原文

訳文

パターンと実践 ディベロパー・センター

Microsoft Prism Library 5.0 for WPFの開発者のガイド原文サイト)から:

コマンド

Commands

トリガとコマンドの相互作用

Interaction Triggers and Commands

非同期相互作用を扱う

Handling Asynchronous Interactions

ユーザーとの対話処理パターン

User Interaction Patterns

高度な構築と接続

Advanced Construction and Wire-Up

MVVMアプリケーションをテストする

Testing MVVM Applications

MVVMアプリケーションからModelとViewModelをテストすることは、他のクラスと同じツールと技術をテストすることと同じです。 -ユニット・テストとモックアップのフレームワークのような、-使用することができます。 しかしながら、いくつかのテスト・パターンは、ModelとViewModelクラス、そして、標準的なテストの技術の恩恵を得ることができます。 そして、ヘルパー・クラスをテストするのが一般的です。

INotifyPropertyChangedの実装をテストする

Testing INotifyPropertyChanged Implementations

INotifyPropertyChangedインターフェイスを実装することは、Viewが、ModelとViewModelから生じる変更に反応できます。 これらの変更は、コントロールで示されるドメイン・データに限定されません。; また、それらは、View Modelの状態のような、Viewを制御するために使用されます。 アニメーションが開始される、あるいは、コントロールが無効にされることが原因です。

簡単な事例

Simple Cases

プロパティは、テスト・コードをテストすることによって、イベントハンドラをPropertyChangedイベントに添付することによって、 直接、更新することができます。そして、プロパティのために、新しい値が設定された後、イベントが発生するかどうか、確認します。 PropertyChangeTrackerクラスのような、ヘルパー・クラスは、ハンドラを接続し、そして、結果を集めるために使用できます。; テストを記述するとき、これは反復的なタスクを避けます。次のコードの例は、この種のヘルパー・クラスを使用して、テストを示します。


var changeTracker = new PropertyChangeTracker(viewModel);

viewModel.CurrentState = "newState";

CollectionAssert.Contains(changeTracker.ChangedProperties, "CurrentState");

一般的に、テストする必要がない、モデル・デザイナーで作成されるコードのような、 コード生成プロセスの結果として得られるプロパティは、 INotifyPropertyChangedインターフェイスが実装されていることを保証します。

計算された、そして、設定できないプロパティ

Computed and Non-Settable Properties

プロパティが、テスト・コードを設定できないとき、-非公開セッターと一緒のプロパティや読取専用、計算されたプロパティのような、 -テスト中でオブジェクトを刺激するテスト・コードの必要性は、プロパティとその対応する通知において変更をさせます。 しかしながら、テストの構造は、より単純な事例のそれと同じです。 次のコードの例に示すように、モデル・オブジェクトの変更が変更するView Modelでプロパティをさせるところ。


var changeTracker = new PropertyChangeTracker(viewModel);

var question = viewModel.Questions.First() as OpenQuestionViewModel;
question.Question.Response = "some text";

CollectionAssert.Contains(changeTracker.ChangedProperties, "UnansweredQuestions");

全部のオブジェクト通知

Whole Object Notifications

あなたが、INotifyPropertyChangedインターフェイスを実装するとき、 それは、オブジェクトのために、オブジェクトのすべてのプロパティが変更されるかもしれない、 変更されたプロパティの名前を示すために、nullや空の文字列でPropertyChangedイベントを発生させることができます。 これらの事例は、ちょうど、それぞれのプロパティの名前に通知する事例のように、テストすることができます。

INotifyDataErrorInfoの実装をテストする

Testing INotifyDataErrorInfo Implementations

IDataErrorInfoインターフェイスを実装する、そして、INotifyDataErrorInfoインターフェイスを実装するプロパティが設定する例外を投げるような、 結合を有効にするために、入力の確認を実行するために、利用できるいくつかの仕組みがあります。INotifyDataErrorInfoインターフェイスを実装することは、はるかな洗練を提供します。 なぜなら、それは、プロパティごとに、複数のエラーと非同期の実行、そして、プロパティ間の妥当性検証をサポートします。;このように、また、それは最も多くのテストを必要とします。

INotifyDataErrorInfoの実装を検証することは、2つの測面があります。:GetErrorsメソッドのための結果が異なって、 満たされる時、ErrorsChangedイベントを発生させることのような、妥当性検証規則が正しく実装されている、 そして、インターフェイスの実装のための必要条件がテストされていることをテストします。

妥当性検証規則をテストする

Testing Validation Rules

妥当性検証ロジックは、一般的に、出力が、入力に依存する場所の自己完結型のプロセスであるため、通常、テストすることが簡単です。 関連するそれぞれプロパティと妥当性検証規則のために、GetErrorsメソッドと有効な値、無効な値、境界値、 等々のための検証されたプロパティ名を呼び出す結果を検証する必要があります。妥当性検証ロジックが共有される場合、 宣言的にデータの注釈の妥当性検証属性を使用する、妥当性検証規則を表すように、 より徹底的なテストは、共有された妥当性検証ロジックに集中することができます。 一方で、ユーザー定義した妥当性検証規則は、完全に検証する必要があります。


// Invalid case
var notifyErrorInfo = (INotifyDataErrorInfo)question;

question.Response = -15;

Assert.IsTrue(notifyErrorInfo.GetErrors("Response").Cast<ValidationResult>().Any());

// Valid case
var notifyErrorInfo = (INotifyDataErrorInfo)question;

question.Response = 15;
Assert.IsFalse(notifyErrorInfo.GetErrors("Response").Cast<ValidationResult>().Any());

プロパティ間の妥当性検証規則は、同じパターンに準拠しています。 一般的に、異なるプロパティの値の組合せに対応するために、より多くの検証を必要としています。

INotifyDataErrorInfoの実装のための必要条件をテストする

Testing the Requirements for INotifyDataErrorInfo Implementations

GetErrorsメソッドのための正しい値を生成する以外に、INotifyDataErrorInfoインターフェイスの実装は、ErrorsChangedイベントが、 GetErrorsのための結果が、いつ異なるかのような、適切に発生することを確認する必要があります。 さらに、HasErrorsプロパティは、インターフェイスを実装するオブジェクトのすべてのエラーの状態を反映する必要があります。

INotifyDataErrorInfoインターフェイスを実装することは、必須の方法ではありません。 しかしながら、実装は、妥当性検証エラーを格納するオブジェクトに依存します。 そして、必要な通知が実行されることは、一般的に、好まれます。なぜなら、それらは、テストするのが、より簡単です。 このような理由で、それは、確かめる必要がありません。INotifyDataErrorInfoインターフェイスのすべてのメンバーのための必要条件は、 それぞれの検証されたプロパティの上で、それぞれの妥当性検証規則のために満たされています。 (もちろん、エラー管理オブジェクトが適切に検証されている限り)。

インターフェイスの必要条件を検証することは、少なくとも次に示す検証が含まれる必要があります。:

  • HasErrorsプロパティは、オブジェクトの全体的なエラーの状態を反映します。 他のプロパティが、それでも、無効な値を持つ場合、前もって、無効なプロパティを有効な値に設定することは、 このプロパティの変更の結果になりません。
  • GetErrorsメソッドのための結果の変更によって、反映されるように、プロパティの変更がエラー状態のとき、 ErrorsChangedイベントは、発生します。エラー状態の変更は、有効な状態(つまり、エラーでない)から無効な状態、 そして、逆もまた同様に、移行することができます。 あるいは、それは、無効な状態から異なる無効な状態へ移行できます。GetErrorsのための更新された結果は、 ErrorsChangedイベントのハンドラのために利用できます。

INotifyPropertyChangedインターフェイスのための実装をテストするとき、MVVMサンプル・プロジェクトのNotifyDataErrorInfoTestHelperクラスのような、 ヘルパー・クラスは、反復的な管理操作と標準的な検査を取り扱うことによって、通常、より簡単なINotifyDataErrorInfoインターフェイスの実装のために、書き込みテストを作成します。 いくつかの種類の再使用できるエラー・マネージャに依存することなく、インターフェイスが実装されるとき、それらは、とても便利です。次のコードの例は、この種のヘルパー・クラスを示します。


var helper = 
    new NotifyDataErrorInfoTestHelper<NumericQuestion, int?>(
        question, 
        q => q.Response);

helper.ValidatePropertyChange(
    6, 
    NotifyDataErrorInfoBehavior.Nothing);
helper.ValidatePropertyChange(
    20, 
    NotifyDataErrorInfoBehavior.FiresErrorsChanged 
    | NotifyDataErrorInfoBehavior.HasErrors 
    | NotifyDataErrorInfoBehavior.HasErrorsForProperty);
helper.ValidatePropertyChange(
    null,
    NotifyDataErrorInfoBehavior.FiresErrorsChanged
    | NotifyDataErrorInfoBehavior.HasErrors
    | NotifyDataErrorInfoBehavior.HasErrorsForProperty);
helper.ValidatePropertyChange(
    2,
    NotifyDataErrorInfoBehavior.FiresErrorsChanged);

非同期サービスコールをテストする

Testing Asynchronous Service Calls

MVVMパターンを実装するとき、View Modelは、通常、多くの場合、非同期で、サービスに関する操作を呼び出します。 実際のサービスのための代替として、コードのためのテストは、一般的に、モックやスタブを使用する、これらの操作を呼び出します。

非同期動作を実装するために使用される、標準パターンは、そのステータスの操作が発生するための通知のスレッドに関して異なる保証を提供します。 それにもかかわらず、イベントに基づいた非同期デザインパターンは、イベントが、アプリケーションのために適切な、スレッドの上で呼び出されるためのハンドラを保証します。 IAsyncResultデザインパターンは、UIスレッドに投稿されたViewに影響を及ぼす、 どんな変更でも確認するために、呼び出しを始める、View Modelコードを強制するそのような保証を提供しません。

スレッドに関係する処理は、より複雑で、そして、したがって、通常、検証するのがより難しいコードを要求します。 また、それは、通常、非同期であることを、テスト自体に要求します。通知が、UIスレッドで発生すると保証されるとき、 いずれかの理由で、標準的なイベントに基づく非同期パターンは、使用されます。あるいは、なぜなら、View Modelは、 適切なスレッドに通知を整理するために、サービス・アクセス層に依存しています。 テストは、簡素化することができ、そして、基本的に、「UIスレッドのためのディスパッチャ」の役割を実行することができます。

サービスの方法は、それらの操作を実装するために使用される、非同期イベント・パターンに依存する、モックアップを作ります。 メソッドに基づいたベース・パターンが使用される場合、 サービス・インターフェイスのためのモックは、通常十分な標準的なモックアップのフレームワークを使用して作成されます。 しかし、ユーザー定義したクラスのモックに基づいて、イベントに基づくパターンが使用される場合、 それは、通常、好まれるサービス・イベントのための追加と除去操作のためのメソッドを実装しています。

次のコードの例は、サービスのためのモックを使用したUIスレッドで、非同期動作の通知の正常に完了した適切な動作のテストを示します。 この例では、それが、非同期サービスコールを作成するとき、テスト・コードは、View Modelで、指定されるコールバックを捕まえます。 テストは、続いて、コールバックを呼び出すことで、テストで、後に呼び出した完了をシミュレーションします。 このアプローチは、コンポーネントを検証できます。それは、あなたのテストを非同期で作成する複雑さのない、非同期サービスを使用します。


    .Setup(
        r => 
            r.SubmitQuestionnaireAsync(
                It.IsAny<Questionnaire>(), 
                It.IsAny<Action<IOperationResult>>()))
    .Callback<Questionnaire, Action<IOperationResult>>(
        (q, a) => callback = a);
 
uiServiceMock
    .Setup(svc => svc.ShowView(ViewNames.QuestionnaireTemplatesList))

    .Callback<string>(viewName => requestedViewName = viewName);
submitResultMock
    .Setup(sr => sr.Error)
    .Returns<Exception>(null);
CompleteQuestionnaire(viewModel);
viewModel.Submit();
// Simulate callback posted to the UI thread.
// UIスレッドに投稿されるコールバックをシミュレーションします。
callback(submitResultMock.Object);
// Check expected behavior – request to navigate to the list view.
// 期待される動作を確認します-リストViewを操作するために要求します。
Assert.AreEqual(ViewNames.QuestionnaireTemplatesList, requestedViewName);

備考

この検証の方法を使用することは、テストの下で、オブジェクトの機能の能力を働かせるだけです。; コードが、安全なスレッドであるかは、テストをしません。

詳細情報

More Information

Copyright (C) 2011-2016 kukekko All Rights Reserved.
kukekko@gmail.com
ご連絡の際はアドレスの@は半角にしてください。 また、お問い合わせページのURLの明記をお願いします。
「掲載内容は私自身の見解であり、所属する組織を代表するものではありません 」。
inserted by FC2 system