2016-03-22 1 views
0

非同期メソッドを含むNUnitでクラスをテストしようとしました。私は正しい方法でそれを行う方法を知らない。 非同期メソッドで設定されたテストプロパティ

は、私はそれを持つクラスは、次のようになります:

public class EditorViewModel:INotifyPropertyChanged 
{ 
    public void SetIdentifier(string identifier) 
    { 
     CalcContentAsync(); 
    } 

    private async void CalcContentAsync() 
    { 
     await SetContentAsync(); 
     DoSomething(); 
    } 

    private async Task SetContentAsync() 
    { 
     Content = await Task.Run<object>(() => CalculateContent()); 
     RaisePropertyChanged("Content"); 
    } 

    public object Content { get; private set; } 

    ... 
} 

どのように私は、NUnitの中にテストを書くことができることをチェックし、コンテンツ属性が正しい値に設定されていること?私はそのようなことをしたい:

[Test] 
public void Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    var viewModel = new EditorViewModel(); 

    viewModel.SetIdentifier("XXX"); 

    Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
} 

しかし、それは動作しません。非同期コードはアサーションの前に実行されていないためです。

+0

SetIdentifierに非同期がないという誤植はありますか? – Domysee

+0

@Domyseeそれは他の方法でコンパイルできないので私はそう思います。 –

+0

[非同期無効](http://haacked.com/archive/2014/11/11/async-void-methods/)。真剣に - これをしないでください。それをテストすることはできません。呼び出しコードは完了するまで待つことはできません。 –

答えて

1

あなたSetIdentifier方法があまりにもasyncである(あるいはあなたがその中に操作を待つので、あなたが次にあなたの方法は、次のいずれかのように見えることができ、それasync行う必要があります。

public async Task SetIdentifier(string identifier) 
{ 
    await SetContentAsync(); 
    DoSomething(); 
} 

そして今、あなたはあなたにそれをただ待つことができます。ユニットテスト:

[Test] 
public async Task Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    var viewModel = new EditorViewModel(); 

    await viewModel.SetIdentifier("XXX"); 

    Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
} 

あなたはまた、同期的にテストを呼び出すために回避策を使用することができます。

[Test] 
public async Task Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    Task.Run(async() => 
    { 
     var viewModel = new EditorViewModel(); 

     await viewModel.SetIdentifier("XXX"); 

     Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
    }).GetAwaiter().GetResult(); 
} 

Via MSDN Magazine

+0

あなたの答えをありがとう。コードを少し変更しました。なぜなら、私は方法を見逃してしまったからです。おそらく '非同期void 'が問題です。 – scher

+0

'async void'は問題の一部です。 async voidは、非同期コードを実行したいが結果を待たないことを示します。結果を待っていない場合は、テストのセットアップが完了する前に、テストは続行され、テストが実行されます。イベントコードがイベントのエミッタ(メッセージループなど)をブロックしないようにするため、async voidは主にイベントに使用されます。テストするときは、作業を完了するまで待つ必要があるため、テストする前に 'async Task'を使用する必要があります。テストメソッドは非同期タスクでもなければならず、NUnitはテストの結果を待つことができます。 –

0

asyncを使用している場合は、には常にタスクを返す必要があります。それ以外の場合は「火災と忘れ」となり、Taskと対話する方法は全くありません。

そのため、あなたはこのように、Taskを返すようにSetIdentifierの署名を変更する必要があります。

public async Task SetIdentifier(string identifier) 
{ 
    await SetContentAsync(); 
    DoSomething(); 
} 

次にあなたがテストで操作が完了するのを待つことができます。

[Test] 
public async void Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    var viewModel = new EditorViewModel(); 

    await viewModel.SetIdentifier("XXX"); 

    Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
} 

あるいは、もしテストランナーはasyncをサポートしていません。

[Test] 
public void Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    var viewModel = new EditorViewModel(); 

    viewModel.SetIdentifier("XXX").Wait(); 

    Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
} 
関連する問題