2011-11-12 4 views
6

NUnitを使用してカスタムWPFコントロールを単体テストしようとしています。コントロールはリストのボタンのListViewです(DataContextはコントロールのコンストラクターに設定されています)。WPFでデータバインディングをユニット単位でテストする

私は、(例えば)リストに項目を追加し、新しいボタンがビューに追加されることを確認するなどのテストを書いたいと思います。しかし、NUnitテストのリストに項目を追加すると、それでもListViewが空であると報告します。私のアプリを実行すると、すべて正常に動作します。

以下の関連コードを記載しました。これをテストするには何をする必要がありますか?

XAML:

<ListView x:Class="SoundBlock" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      ItemsSource="{Binding Path=Sounds}"> 
    <ListView.ItemTemplate> 
     <DataTemplate> 
      <Button Content="{Binding Title}" /> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

クラス定義

public partial class SoundBlock : ListView 
{ 
    public SoundBlock(Board xiBoard) 
    { 
     // Initialize. 
     InitializeComponent(); 

     // Set the data context for this block. 
     DataContext = xiBoard; // Board has an ObservableCollection<Sound> 
           // property called Sounds. 
    } 
} 

テストケース

[Test] 
public void TestAddSound() 
{ 
    board = new Board(); 
    block = new SoundBlock(board); 
    Assert.AreEqual(0, block.Items.Count); 

    sound = new Sound("sound.mp3"); 
    board.Sounds.Add(sound); 
    Assert.AreEqual(1, block.Items.Count); // This fails - count is still 0 
} 

答えて

4

私の質問を参照してください:あなたが結合強制する必要Force binding in WPF

をコントロールが表示されるまで、それは動作しません。新しいウィンドウに配置してウィンドウを表示することができます。

+0

素晴らしい作品です。ありがとう! –

0

あなたをバインドさので、 ItemSourceをListに追加すると、ListにはINotifyCollectionChangedが実装されていないため、コレクションの変更はUIコントロールに伝播されないため、UIに変更は表示されません。

List<Sound>の代わりにObservableCollection<Sound>を使用することができます。 ObservableCollectionは内部的にINotifyCollectioChangedインターフェイスを実装します。

+0

まだ試したことがない、私は恐れている! –

+0

あなたのアプリケーションを実行している間、私はあなたが最初にこのリストを初期化する前にそれを推測していると推測しています。コントロールの初期化後にアイテムを追加しようとすると、余分なボタンは表示されません。 –

+0

申し訳ありませんが、私は明確にする必要があります - 私はObservableCollectionにリストを変更し、私のアプリケーションでは、初期化後に項目を追加しました。これは正常に動作します。しかし、ユニットテストは依然として壊れています。 –

3

私は正確に何が起こっているのか、そしてなぜうまくいくのかは分かりませんが、この小さなヘルパークラスを使ってテストするコントロールのデータコンテキストを設定すると、うまくいきます。

public class DataContextHelper 
{ 
    public static void InjectDataContext(object element, object dataContext) 
    { 
     if (dataContext == null) 
      return; 
     if (element is FrameworkContentElement) 
      ((FrameworkContentElement)element).DataContext = dataContext; 
     else if (element is FrameworkElement) 
      ((FrameworkElement)element).DataContext = dataContext; 

     TriggerUpdateOfInMemoryView(); 
    } 

    /// <summary> 
    /// Triggers an update to a view that exists only in memory, not on the screen. 
    /// </summary> 
    /// <remarks> 
    /// When setting data context or modifying the control tree of a view that exists in 
    /// memory, then those changes are not automatically visible when e.g. attempting to 
    /// print the view. This function will trigger the update of the view so, e.g. a print 
    /// will display the updated view. 
    /// </remarks> 
    public static void TriggerUpdateOfInMemoryView() 
    { 
     var dispatcher = Dispatcher.CurrentDispatcher; 
     dispatcher.Invoke(
      DispatcherPriority.SystemIdle, 
      new DispatcherOperationCallback(arg => null), 
      null); 
    } 
} 
+0

これは素晴らしいですが、それ以外の場合は 'TriggerUpdateOfInMemoryView'を呼び出す必要がありますか?バインディングが自動的にビューを変更していることをテストすることがポイントであれば、手動で更新を強制的に強制する必要があります。 –

+0

これは素晴らしい解決策です。ウィンドウを強制するよりはるかに良い。 – on3al

関連する問題