测试 属性 由异步方法设置

Testing property set by async method

我尝试使用包含异步方法的 NUnit 测试 class。我不知道如何以正确的方式做到这一点。

我有一个 class 看起来像这样:

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 中编写测试,检查 Content-属性 是否设置为正确的值?我想做这样的事情:

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

    viewModel.SetIdentifier("XXX");

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

但这不起作用。因为断言之前异步代码还没有执行。

你的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.

使用 async 时,您应该始终 return 一个任务。否则它将是 "fire and forget",并且您绝对无法与 Task.

进行交互

因此您应该将 SetIdentifier 的签名更改为 return a 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>());
}