You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步方法单元测试:如何触发事件并验证MyViewModel的InfoList填充?

测试MyViewModel时避免重复InfoLoader配置的方案

你不需要重复配置真实的InfoLoader,因为MyViewModel的测试核心是验证它正确响应IInfoLoader的事件并填充InfoList,而非关心IInfoLoader内部如何读取文件生成数据。直接MockIInfoLoader接口即可,完全隔离对FileSystem的依赖,同时避免重复代码。

具体实现步骤

  1. 准备预期的测试数据:创建你期望最终出现在InfoList中的MyInfo集合。
  2. MockIInfoLoader:
    • 配置LoadInfoAsync方法返回已完成的Task。
    • 在LoadInfoAsync被调用时,手动触发InfoLoaded事件,将预期的MyInfo逐个传入。
  3. 实例化MyViewModel并执行测试逻辑,最后验证InfoList与预期一致。

完整测试代码

[TestMethod]
public async Task MyViewModel_StartLoadInfoAsync_Success()
{
    // 1. 准备预期数据
    var expectedInfoList = new List<MyInfo>
    {
        new MyInfo("name1"),
        new MyInfo("name2")
    };

    // 2. Mock IInfoLoader
    var mockInfoLoader = new Mock<IInfoLoader>();
    
    // 配置LoadInfoAsync:当方法被调用时,触发InfoLoaded事件传入所有预期的MyInfo
    mockInfoLoader.Setup(loader => loader.LoadInfoAsync())
        .Returns(() =>
        {
            foreach (var info in expectedInfoList)
            {
                mockInfoLoader.Raise(loader => loader.InfoLoaded += null, info);
            }
            return Task.CompletedTask;
        });

    // 3. 执行测试逻辑
    var vm = new MyViewModel(mockInfoLoader.Object);
    await vm.StartLoadInfoAsync();

    // 4. 验证结果:将ObservableCollection转为List后对比
    var actualInfoList = vm.InfoList.ToList();
    CollectionAssert.AreEqual(expectedInfoList, actualInfoList);
}

为什么这么做?

  • 关注点分离:InfoLoader的逻辑已经在单独的测试中验证过,ViewModel测试只需要确保它正确处理IInfoLoader的事件和方法调用。
  • 避免重复配置:不需要再重复创建FileSystem的Mock、设置文件读取逻辑,大幅简化测试代码。
  • 隔离依赖:完全隔离了文件系统等外部依赖,测试更稳定、执行更快。

额外注意事项

  • 如果MyInfo没有重写Equals和GetHashCode,CollectionAssert.AreEqual会比较引用而非值,这时需要自定义比较器,或者逐个验证属性是否一致。
  • 使用Moq的Raise方法触发事件时,要注意事件委托的签名必须匹配(这里是Action<MyInfo>,所以传入单个MyInfo参数即可)。

内容的提问来源于stack exchange,提问作者theateist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 10:54:14