【问题标题】:Testing Asynchronous/Callbacks Visual Studio测试异步/回调 Visual Studio
【发布时间】:2026-01-07 10:20:08
【问题描述】:

我需要为一大堆类似于以下示例的 C# 代码编写一些测试。这是我在 C# 中的第一个任务,我很不幸被直接转储到异步代码中:(。它是一个发出一堆数据库请求的 Web 应用程序:

namespace Foo.ViewModel
{
    public class FooViewModel
    {
        private ManagementService _managementService;
        public int Status { get; set; }
        public Foo()
        {
            Status = 5;
            _managementService = new ManagementService();
            _managementService.GetCustomerInfoCompleted += new EventHandler<GetCustomerInfoEventArgs>(CustomerInfoCallback);

        }

        public void GetCustomerInfo(int count)
        {
            int b;
            if (someCondition() || otherCondition())
            {
                b = 2;
            }
            else
            {
                b = SomeOtherAsynchronousMethod();
            }
            _managementService.GetCustomerInfoAsync(b, count);
            //when completed will call CustomerInfoCallback
        }

        void CustomerInfoCallback(object sender, GetCustomerInfoEventArgs args)
        {
            Status = args.Result.Result.Total;
            UpdateView();
        }

    }

}

我希望能够像这样运行一个简单的测试:

    [TestMethod]
    public void TestExecute5()
    {
        Foo f = new Foo();
        f.GetCustomerInfo(5);
        Assert.AreEqual(10, f.Status);
    }

但显然使用异步方法并不那么简单。

ManagementService 中可能有 40 个异步方法,由大约 15 个不同的 ViewModel 调用 - 这个 ViewModel 调用其中大约 8 个异步方法。异步调用是通过基于事件的异步模式实现的,因此我们没有任何好的“异步”或“等待”函数。

我可以做些什么来让测试以某种方式工作,我可以调用 GetCustomerInfo 方法并在回调完成后检查状态?

【问题讨论】:

标签: c# testing asynchronous integration-testing


【解决方案1】:

如果您要测试一个事件是否被触发,您需要一种进入事件处理程序的方法。由于您使用integration-testsing 标记了您的问题,我假设您想测试服务和视图模型是否可以正常工作。如果您允许将依赖项注入到您的视图模型中,您可以这样构建:

public class ViewModel
{
    private readonly ManagementService _managementService;
    public ViewModel(ManagementService service)
    {
        _managementService = service;
    }

    public void DoSomething()
    {
        _managementService.DoWork();
    }

}

public class ManagementService
{
    public event EventHandler SomethingHappened;

    public void DoWork()
    {
        System.Threading.Thread.Sleep(2000);
        if (SomethingHappened != null)
            SomethingHappened(this, null);
    }
}

然后当你去测试你的视图模型和服务时,你可以这样做:

[TestMethod, Timeout(5000)]
public void TestMethod1()
{
    var testManagementService = new ManagementService();
    AutoResetEvent evt = new AutoResetEvent(false);
    testManagementService.SomethingHappened += delegate (System.Object o, System.EventArgs e)
    {
        evt.Set();
    };

    var vm = new ViewModel(testManagementService);
    evt.WaitOne();
}

【讨论】: