2016-03-22 39 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(); 
} 

通過MSDN Magazine

+0

感謝您的回答。我改變了一下代碼,因爲我錯過了一個方法。也許'異步空白'是問題。 – scher

+0

'async void'是問題的一部分。 async void表示您想要異步運行代碼,但不要等待結果。如果您沒有等待結果,您的測試將繼續並在您的測試設置完成之前運行測試。 async void主要用於事件,因爲您不希望事件代碼阻塞事件的發射器(如消息循環)。在測試時,您必須使用'async Task',因爲在測試之前您必須等待工作完成。您的測試方法也必須是異步任務,以便NUnit可以等待並檢查測試結果。 –

0

當與async一起工作時,您應該總是返回一個任務。否則,它會是「火災和遺忘」,你絕對沒有辦法與Task互動。

因此,你應該改變SetIdentifier的簽名返回一個Task,像這樣:

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>()); 
}