2011-01-30 5 views
12

私はTDDを初めて使っています。私は、ビュー・モデルで必要なプロパティをプレーン・オート・プロパティとして作成し始めました。Viewmodelのユニットテスト

public string Firstname { get; set; } 

その後、私はその後、私はテストはこのように合格するために実際の実装を延長するテスト

[TestMethod] 
[Tag("Property")] 
public void FirstNameTest() 
{ 
    ViewModel = new CustomerViewModel(); 
    ViewModel.PropertyChanged += (s, e) => 
            { 
             Assert.AreEqual("Firstname", e.PropertyName); 
             Assert.AreEqual("Test", ViewModel.Firstname); 
            }; 
    ViewModel.Firstname = "Test"; 
} 

を作成します。

public string Firstname 
{ 
    get { return _contact.FirstName; } 
    set 
    { 
     if (_contact.FirstName == value) 
      return; 

     _contact.FirstName = value; 

     RaisePropertyChanged(() => Firstname); 
    } 
} 

私が持っている問題は、テストはまだ合格ということですAutプロパティの場合。どのように私のプロセスを改善することができる私のための任意のヒント?

+3

ラムダ内にアサートを配置しないでください。アサートは、失敗したときに例外をスローします。あなたがラムダ内でそれを行うと、それらはテスト中のオブジェクトの内部で起動し、オブジェクトによって処理されるリスクを実行します。その代わりに、テストスコープの一部の(通常はbool)変数に結果を割り当ててから、コールスタックを戻したり解凍したときに結果をアサートしたりする必要があります。 – Tormod

答えて

5

あなたは非同期にテストを書いてみてください。このテスト方法を検討してください。

[TestMethod] 
[Asynchronous] 
public void TestMethod1() 
{ 
    TestViewModel testViewModel = new TestViewModel(); 

    bool firstNameChanged = false; 

    testViewModel.PropertyChanged += 
     (s, e) => 
      { 
       if (e.PropertyName == "FirstName") 
       { 
        firstNameChanged = true; 
       } 
      }; 

    EnqueueCallback(() => testViewModel.FirstName = "first name"); 
    EnqueueConditional(() => firstNameChanged == true); 
    EnqueueTestComplete(); 
} 

メソッドの上部にある非同期属性に注目してください。 EnqueueCallbackとEnqueueTestCompleteの2つの重要なメソッドがあります。 EnqueueCallbackはラムダ式をキューに追加し、テストメソッドは現在のコールバックが実行されるまで待機します。ここでは、ViewModelのPropertyChangedイベントを購読し、FirstNameプロパティが変更を通知するときに、ローカルブール変数をtrueに設定します。次に、FirstNameプロパティを設定するコールバックと、ローカルブール変数が値を変更したことをアサートするコールバックの2つのコールバックをエンキューします。最後に、EnqueueTestComplete()の呼び出しを追加して、フレームワークがテストが終了したことを知る必要があります。

注:EnqueueCallbackとEnqueueTestCompleteを取得するには、テストクラスのSilverlightTestから継承する必要があります。また、Microsoft.Silverlight.Testingをインポートして非同期属性を取得する必要があります。ここで

using Microsoft.Silverlight.Testing; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace Foo.Example.Test 
{ 
    [TestClass] 
    public class Tests : SilverlightTest 
    { 

     // ... tests go here 
    } 
} 
+1

ありがとうございました。この回答はSilverlightレベルでさらに役立ちました。しかし、EnqueueConditionalを使用せずにEnqueueCallbackを使用した場合は、いずれにしても呼び出しを同期化する場合と同じになります。 – Houman

+0

はい、EnqueueConditionalを使用して、実際にイベントが発生するまで待機する必要があります。私は私の例をあまりにも些細なものにしたと思います。私の謝罪です。 EnqueueConditionalを使用して、firstNamedChangedのブール状態がtrueになるのを待機するようになりました。 – avanek

2

実際にPropertyChangedが起動することを実際にアサートする別のテストが必要です。

このテストを行うと、イベントが発生しないため、自動プロパティが失敗するはずです。

Here's an example of how to do that in Moq

+0

多くの記事この記事のおかげで、私はすぐにそれを学び、他にそれから学ぶことができるものを見ていきます。 – Houman

10

あなたはこのような何かを行うことができます。

[TestMethod] 
    [Tag("Property")] 
    public void FirstNameTest() 
    { 
     bool didFire = false; 
     ViewModel = new CustomerViewModel(); 
     ViewModel.PropertyChanged += (s, e) => 
             { 
              didFire = true; 
              Assert.AreEqual("Firstname", e.PropertyName); 
              Assert.AreEqual("Test", ViewModel.Firstname); 
             }; 
     ViewModel.Firstname = "Test"; 
     Assert.IsTrue(didFire); 
    } 
+0

多くの方は、明確な答えをありがとうございます。それは今働く。しかし、Assertは最後の行でAssertFailedExceptionをスローします。私はF5にそれを継続させなければならない。そしてテストが結果に失敗したのを見る。私はVS 2010に付属しているSilverlight 4ユニットテストツールキットを使用しています。これは非常に面倒です。これを抑止することは可能ですか、後で何か問題が生じた場合は50ユニットテストでF5したくありません。 :) – Houman

+1

単にデバッグモードでテストを実行しないでください:) –

+0

リリースの下で実行しましたが、それでも中断が発生します。非常に迷惑な。私はSilverlight 4 Test Frameworkの下で単体テストを使用しています。誰かアイデア? – Houman

2

テストは、行動しない限り、それはテストがすでに実装されている失敗するはずです。私の最後の試みで、試験のプロパティ変更通知を

、私は私がこのようなテストを書く助けたことa helper classを作成した(これは、NUnitのであります)

[Test] 
public void NotifiesChangeIn_TogglePauseTooltip() 
{ 
    var listener = new PropertyChangeListener(_mainViewModel); 

    _mainViewModel.TogglePauseCommand.Execute(null); 

    Assert.That(listener.HasReceivedChangeNotificationFor("TogglePauseTooltip")); 
} 
1

は、私は(それは少し異なる場合がありますので、私はNUnitのを使用しました)、過去にこれをやった方法は次のとおりです:

[Test] 
public void ShouldNotifyListenersWhenFirstNameChanges() 
{ 
    var propertiesChanged = new List<string>(); 

    ViewModel = new CustomerViewModel(); 
    ViewModel.PropertyChanged += (s, e) => propertiesChanged.Add(e.PropertyName); 

    ViewModel.Firstname = "Test"; 

    Assert.Contains("Firstname", propertiesChanged);  
    Assert.AreEqual("Test", ViewModel.Firstname); 
} 

がいいの側面を有することが次のようになります - 変更されたものをデバッグして解決できることの影響。Firstnameではない場合。他のフィールドから複数のフィールドが計算されていると便利です。また、あなたのコード内での行動の他の側面を見ることができます。

[Test] 
public void ShouldNotNotifyListenersWhenPropertiesAreNotChanged() 
{ 
    var propertiesChanged = new List<string>(); 

    ViewModel = new CustomerViewModel(); 
    ViewModel.Firstname = "Test"; 

    ViewModel.PropertyChanged += (s, e) => propertiesChanged.Add(e.PropertyName); 

    ViewModel.Firstname = "Test"; 

    Assert.AreEqual(0, propertiesChanged.Count); 
} 
-1

おそらく、そこに明らかにされていない、このコードへのより多くの背景があるが、私は見ていますが、不必要に複雑なようです。なぜ、RaisePropertyChangedイベントに繋がるの?設定後、プロパティをチェックしてください。

[TestMethod] 
[Tag("Property")] 
public void FirstNameTest() 
{ 
    var expected = "John"; 
    var sut = new CustomerViewModel(); 

    sut.Firstname = expected; 

    Assert.AreEqual(expected, sut.Firstname); 
} 

これにより、テストが真の単体テストに変わります。

+0

これはやや役に立たないでしょう。なぜフレームワークが自動作成の設定者を正しく処理できるのでしょうか?テストは、 'PropertyChanged'イベントが期待どおりに発生していることを確認する瞬間に意味をなさないようになります。 **そのようなテストでは、チェックの価値があるのは唯一のものです。 – Martin

+0

@Martin私はautopropertyの設定者をテストすることは何の利益ももたらさないことに同意するでしょう。しかし、元のコード(Hoomanによって投稿されたもの)を見ると、入力値が_contact.FirstNameの値と等しくない場合にのみプロパティが設定されます。それが私のリファクタリングされたテストに関するコードの一部です。 – hitopp