2011-08-19 10 views
11

私はUserControlLoadedイベントにEventAggregatorというメッセージを発行しています。これをテストして(そしてイベントを発生させたLoadedを取得するため)、私は現在、ウィンドウを作成してそれにコントロールを追加してから、Loadedイベントが発生するのを待っています。WPFコントロールをウィンドウに追加しないでテストする

コントロールを作成してウィンドウに追加することなくLoadedイベントが発生するようにテストを設定する方法はありますか?例えば

[Test, RequiresSTA] 
public void active_thingy_message_is_published_on_loaded() 
{ 
    const string TestMsg = "Active thingy changed"; 

    using (AutoResetEvent loadedEvent = new AutoResetEvent(false)) 
    { 
     DummyEventService eventService = new DummyEventService();     
     DummyControl control = new DummyControl(eventService, TestMsg); 
     control.Loaded += delegate { loadedEvent.Set(); }; 

     Assert.That(eventService.Message, Is.Null, "Before."); 
     Window window = new Window { Content = control }; 
     window.Show();     
     loadedEvent.WaitOne(); 
     window.Dispatcher.InvokeShutdown(); 
     Assert.That(eventService.Message, Is.EqualTo(TestMsg), "After."); 
    } 
} 

private class DummyControl : UserControl 
{ 
    public DummyControl(DummyEventService eventService, string testMsg) 
    { 
     Loaded += delegate { eventService.Publish(testMsg); }; 
    } 
} 

private class DummyEventService 
{ 
    public string Message { get; private set; } 
    public void Publish(string msg) { Message = msg; } 
} 

更新

私は「 "...テスト" に "ユニットテスト..." からタイトルを変更して、タグを交換しました手段 - 前記テスト "と"テスト "。

私は建設的ではないので、これがどのクラスのテストであるか正確に分けないほうがいいでしょう。はい、これは「単体テスト」ではないと主張できますが、それは役に立たないことです。コントロールのライフサイクルに依存する問題をテストしたいと思います。これにはLoadedイベントが含まれています。これは重要な回帰テストです。第三者のコンポーネントとして、私はLoadedで発生したメッセージに依存して制御できません。

ウィンドウにコントロールを追加せずにLoadedイベントを発生させることはできますか?

+0

ウィンドウを擬似/モックする必要があります...しかし、これはもはや単体テストのようには見えません。 –

+0

@Henkどのようにして偽のウィンドウが表示され、私のユーザコントロールがロードされ、その結果、 'Loaded'イベントが発生しますか?あなたは、リフレクション経由Loadイベントを上げてみてください –

+0

: http://stackoverflow.com/questions/198543/how-do-i-raise-an-event-via-reflection-in-net-c –

答えて

6

ターゲットコントロールのLoadedイベントを発生させたい場合は、Reflectionがそのトリックを行う必要があります。

public static void RaiseLoadedEvent(FrameworkElement element) 
{ 
    MethodInfo eventMethod = typeof(FrameworkElement).GetMethod("OnLoaded", 
     BindingFlags.Instance | BindingFlags.NonPublic); 

    RoutedEventArgs args = new RoutedEventArgs(FrameworkElement.LoadedEvent); 

    eventMethod.Invoke(element, new object[] { args }); 
} 

これは文字通り、各FrameworkElementの中に存在しているOnLoaded方法を発射するので、あなたのテストは、アプリケーションの状態を必要とする場合、これは動作しません。

また、親のLoadedイベントとその子イベントとの間には関係がありません。テストで子要素がLoadedイベントを発生させる必要がある場合、ヘルパーメソッドは手動で子コントロールをウォークしてそれらを起動する必要があります。

+0

+1私は反射に頼らざるを得ないことを望んでいましたが、私の場合、これは合併症はありません。 –

5

Loadedイベントハンドラの内容を独自のメソッドにリファクタリングし、Loadedイベントハンドラで呼び出します。 Loadedイベントではなく、リファクタリングされたメソッドをテストするためのユニットテストを作成します。

ユニットテストでは、ユニットが行うことを確認しています。ユニットが他のユニットとどのように相互運用するかのテストは、統合テストです。統合テストを行い、回帰テスト統合ユニットができることは確かに価値がありますが、それは単体テストとは異なる作業です。

最後に、コントロールのLoadedイベントがロードされたときに(このような統合テストを行う主な理由である)信頼できない場合は、何かが間違っていて、調査する必要があります。

+0

「信頼できない場合」のコメントは+1です。時には、それがあなたに何も買わないなら、独断的に方法論を守らないことが最善です。この場合、おそらくイベントのバインディングを検証するのに十分なコードレビューがあります。 –

+0

もしそうでなければ、どこかに修正が必要な問題があります。 –

+0

@Robert @Merlynタイトルとタグから「ユニット」を削除しました。そのため、テストのどのクラスにぶつかることなく、特に問題をテストしたいのは明らかです。私は独断的ではない。 'Loaded'イベントで公開されているメッセージは、ライフサイクルの観点から非常に重要です。私のシステムでは、他のサードパーティのコンポーネントとメッセージングをどのようにして制御しているのですか?これはどのクラスのテストに挑戦し、解剖するのが魅力的ですが、有効で重要なテストケースである私の問題は解決しません。 –

7

過去2年間で、状況が変わった可能性があります。コードカバレッジのために、私もこの問題に遭遇しました。それは解決策です。

WPF UIElementsは、RaedEventというメソッドを継承します。このメソッドには、RoutedEventArgsが使用されます。これは特定のUIElementの.LoadedEventを使用して構築することができ、最終的なコードカバレッジを得ることができます。

まだ私の答えが必要だとは思っていませんが、誰かがそうするかもしれません。

関連する問題