问题
I try to test a class with NUnit that contains async methods. I don't know how to do it in a correct way.
I have a class with that looks like this:
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; }
...
}
How can I write a Test in NUnit, that checks, that the Content-Property is set to the right value? I want to do something like that:
[Test]
public void Content_WhenModifierIsXXX_ReturnsSomeViewModel()
{
var viewModel = new EditorViewModel();
viewModel.SetIdentifier("XXX");
Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>());
}
But that doesn't work. Because the asynchronous code has not been executed before the assertion.
回答1:
Your SetIdentifier
method is async
too (or you need to make it async
because you wait operation inside it. Then your method can looks like next one:
public async Task SetIdentifier(string identifier)
{
await SetContentAsync();
DoSomething();
}
And now you can just await it in your unit test:
[Test]
public async Task Content_WhenModifierIsXXX_ReturnsSomeViewModel()
{
var viewModel = new EditorViewModel();
await viewModel.SetIdentifier("XXX");
Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>());
}
You can also use workaround to call your test in a sync manner:
[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.
回答2:
When working with async
you should always return a Task. Otherwise it would be "fire and forget", and you have absolutely no way of interacting with the Task
.
Therefore you should change the signature of SetIdentifier to return a Task
, like this:
public async Task SetIdentifier(string identifier)
{
await SetContentAsync();
DoSomething();
}
Then you can wait for the operation to complete in the test:
[Test]
public async void Content_WhenModifierIsXXX_ReturnsSomeViewModel()
{
var viewModel = new EditorViewModel();
await viewModel.SetIdentifier("XXX");
Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>());
}
Or, if your test runner does not support async
:
[Test]
public void Content_WhenModifierIsXXX_ReturnsSomeViewModel()
{
var viewModel = new EditorViewModel();
viewModel.SetIdentifier("XXX").Wait();
Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>());
}
来源:https://stackoverflow.com/questions/36148778/testing-property-set-by-async-method