Testing property set by async method

醉酒当歌 提交于 2019-12-12 05:24:46

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!