【问题标题】:Testing property set by async method测试由 async 方法设置的属性
【发布时间】:2016-03-22 07:50:06
【问题描述】:

我尝试使用包含异步方法的 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 中编写一个测试来检查 Content-Property 是否设置为正确的值?我想做这样的事情:

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

    viewModel.SetIdentifier("XXX");

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

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

【问题讨论】:

  • SetIdentifier 上没有 async 只是一个错字吗?
  • @Domysee 我认为是因为它无法以其他方式编译。
  • Avoid async void。说真的 - 不要这样做。您无法对其进行测试,任何调用代码都无法等待完成。
  • 我不太确定异步和等待。我的意图是在计算内容的同时执行DoSomething() 方法。这不是正确的做法吗?

标签: c# unit-testing async-await nunit


【解决方案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

【讨论】:

  • 感谢您的回答。我稍微更改了代码,因为我错过了一个方法。也许async void 是问题所在。
  • async void 是问题的一部分。 async void 表示您要异步运行代码,但不等待结果。如果您不等待结果,您的测试将继续并在您的测试设置完成之前运行测试。 async void 主要用于事件,因为您不希望事件代码阻塞事件的发射器(例如消息循环)。测试时,必须使用async Task,因为必须等待工作完成才能进行测试。您的测试方法也必须是 async Task 以便 NUnit 可以等待并检查您的测试结果。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 2020-02-21
    • 1970-01-01
    • 2016-11-09
    相关资源
    最近更新 更多