2015-10-20 32 views
5

ユニットテストごとにログインしているユーザーがいるため、テストで非同期呼び出し(ログイン)を強制的に実行する必要がありますSetUpAsync UnitTests in c#

私はこの作業を行う方法を見つけることができません、私はnullポインタの例外、またはセットアップの無効な署名を取得します。

public async void SetUp() {} 

これは、私がログインしていないよので、すべての私のテストは、おそらく私のオブジェクトで失敗します。

public async Task SetUp() {} 

設定が無効の署名を持っているので、すべての私のテストは無視します。

そして、私はそれぞれのテストでセットアップのX行をコピーする必要はありません。それらはまったく同じものなのでセットアップが何であるかはわかります。

私には何が欠けていますか?これは些細な問題のように見えます。ここで

は何か

CreateTicketViewModel _viewModel; 

     [SetUp()] 
     public async void SetUp() //I have tried using Task instead of void 
     { 

      IUserService userService = Dependency.Instance.Resolve<IUserService>(); 
      await userService.LoginAsync(this.UserName, this.Password); 

      _viewModel = Dependency.Instance.Resolve<CreateTicketViewModel>(); 
     } 

     [TearDown()] 
     public void TearDown() 
     { 
      _viewModel = null; // I have tried removing this 
     } 

     [Test()] 
     public void Initialization() 
     { 
      // If I put what's in SetUp here and add "async" before void, 
      // it works just fine 

      Assert.IsNotNull(_viewModel); 
      Assert.IsNotNull(_viewModel.Ticket); 
     } 
+0

私は持っていないSUTに非同期ボイドを持たないことに関する多くのブログ投稿を読んだことがありますが、これらのブログ投稿のどれもがテスト自体について話しません。 デザインに問題はありますか? –

+0

セットアップメソッドの代わりにテストメソッドを非同期にすることはできませんか?あるいは、SetUpメソッドを同期させることさえできます。以前は推奨されています。 –

+0

アサーションのみの非同期テストでは、警告が表示されます。私は可能ならばそれを避けることを望んでいます。 –

答えて

4

ユニットテストフレームワークによっては、asyncを使用すると、フレームワークによってセットアップが正しく処理されないことがあります。

NUnitsの場合私はまだ非同期セットアップ方法をサポートしていないと思う。あなたのセットアップで行う必要がありますだから何

だけで完了するために、ログインのための同期を待つことです。

userService.LoginAsync(this.UserName, this.Password).Wait()

編集:それはそれはまたMSTests用ケースだ未解決の問題https://github.com/nunit/nunit/issues/60

だよう が見えます。

2

を示すのためにあなたは自分の設定方法は、すべての非同期およびこれを書いていない作ることができませんでした、私が今持っているものでしょうか?

+0

これを行うと、テストが開始されたときに自分のuserServiceの内容がnullになり、失敗します。 そのLoginAsyncメソッドの背後には、より多くの非同期呼び出しがあることに注意してください。 –

+0

私はログインを同期して実行するという考えが好きですが、 –

2

非同期セットアップはサポートされていませんが、非同期テストメソッドがサポートされています。セットアップメソッドの代わりにテストメソッドを非同期にすることができます。

[TestFixture] 
public class AsyncSetupTest 
{ 
    private Task<CreateTicketViewModel> viewModelTask; 

    [SetUp()] 
    public void SetUp() 
    { 
     viewModelTask = Task.Run(async() => 
     { 
      IUserService userService = Dependency.Instance.Resolve<IUserService>(); 
      await userService.LoginAsync(this.UserName, this.Password); 

      return Dependency.Instance.Resolve<CreateTicketViewModel>(); 
     }); 
    } 

    [Test()] 
    public async Task Initialization() 
    { 
     CreateTicketViewModel viewModel = await viewModelTask; 

     Assert.IsNotNull(viewModel); 
     Assert.IsNotNull(viewModel.Ticket); 
    } 
} 

アイデアではなくSetup方法で行われ、すべてのセットアップ作業を取得する、我々はセットアップの完了を表すとTest方法でそれを待っているTaskを作成し、です。

この方法では、すべてのセットアップロジックを繰り返すわけではありません。しかし、すべてのテストメソッド内でViewModelをTaskから抽出するだけです。

+0

これはうまくいくでしょうが、すべてのテストで1つの繰り返された行が必要です。しかし確かにそれはすでに私がやったよりも優れています。ありがとうございました。 一方、Dan Dinuの回答は、私のテストで自分のアサーションを持つだけの能力を持つ「現状のまま」動作するソリューションを提供します。これはセットアップ時にコードが少なくなり、コードブロックが小さくなることを意味します。 –

+0

@Zilそれはうまくいくでしょう。しかし、非同期コードをブロックすることは決して良い考えではありません。 [あなたはデッドロックを受ける可能性があります](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html)。 [これも参照してください](http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115163.aspx)。 –

+0

私はプロダクションコードに同意しますが、ログインが進行中のときに私のテストがここで待っていなければなりません。この特定のシナリオでそれが悪いと思いますか?他の非同期呼び出しをここでやっていないことを知っている(ログイン自体の内部ではなく) –