【问题标题】:TestMethod: async Task TestSth() does not work with .NET 4.0TestMethod:异步任务 TestSth() 不适用于 .NET 4.0
【发布时间】:2026-01-27 13:50:01
【问题描述】:

我正在尝试使用 .NET 4.0 BCL Async 和 MsTest 运行异步测试方法。

由于测试用例资源管理器中缺少条目,此设置似乎无法处理 [TestMethod] async Task TestSth()。将签名更改为异步 void 后,我可以运行测试用例,但结果错误(根本不会报告错误)。

我在Running Async Task unit tests with TFS 2010 看到了一个尝试,但我认为应该有一个更漂亮的方法来解决这个问题。

有什么建议吗?

【问题讨论】:

  • “测试用例资源管理器中缺少条目”是什么意思?您的异步测试方法必须返回 Task,而不是 void。
  • VS2010 只是没有内置对异步 [TestMethod] 的支持。除了你提到的斯蒂芬的solution,你为什么认为VS2010有更好的方法?使用 VS2012+(因此使用 TFS2012+),有对此的内置支持。
  • 感谢 cmets!我已经在使用 VS 2013,但是通过以 .NET 4.0 为目标,异步任务方式是不可能的。这就是我所说的“缺少条目”的意思——我根本无法启动测试用例。 @Noseratio:斯蒂芬的解决方案还可以——我只是在寻找一个像另一个“神奇”NuGet-Package 或类似的解决方案,而不是包装每个测试方法;-)
  • @PhilippP,我不明白为什么它不可能。 async 关键字不会更改方法的签名,它只是在 .NET 4.5 或 .NET 4.0 中返回 Task 的方法。您的单元测试项目中的 .NET 目标版本是什么?
  • @Noseratio,是的,如果我重新定位到 4.5,它就可以工作 - 不幸的是,我们必须为整个项目使用 .NET 4.0 :-( 似乎没有其他方法可以像使用 Task.Wait () 解决方法,如斯蒂芬的解决方案。感谢您的帮助!

标签: c# unit-testing .net-4.0 async-await mstest


【解决方案1】:

您只能将 async 关键字与面向 .NET 4.5 的 MSTest 引用类库一起使用。

如果您出于某种原因无法使用 .NET 4.5,那么您将不得不手动等待任务。

即使生产代码(即被测试的代码)不能使用.NET 4.5,为什么测试项目不能这样做呢?如果您已经有 VS 2012+ 可供您使用,那么 .NET 4.5 将安装在您的开发机器上。

【讨论】:

    【解决方案2】:

    这是一个对我有用的解决方法。弄清楚有点棘手,但最终所有针对我的 .NET 4.0 库的单元测试都被检测到并显示在测试资源管理器中,运行和通过,它们都按照正常的async Task 方法编写,没有任何特殊测试运行器、包装器或第三方依赖项。

    1. 将单元测试项目的目标框架更改为 .NET 4.5。
      • 是的,即使项目引用您正在测试的目标是 .NET 4.0,您也必须这样做。
    2. 从您的单元中删除 Microsoft.BclMicrosoft.Bcl.BuildMicrosoft.Bcl.Async NuGet 包引用测试项目。如果您还没有添加这些引用,那么只需不要将它们添加到您的单元测试项目
    3. System.Runtime.dllSystem.Threading.Tasks.dll 作为项目根目录中的链接文件添加到您的 单元测试项目目录。
      1. 在解决方案资源管理器中用鼠标右键单击您的单元测试项目
      2. 添加 > 现有项目...
      3. 浏览到解决方案的包文件夹并找到 Microsoft.Bclnet40 包文件夹;例如,...\packages\Microsoft.Bcl.1.1.10\lib\net40\
      4. 在文件类型下拉菜单中选择所有文件 (*.*)
      5. 按住 Ctrl 键,鼠标左键单击 System.Runtime.dllSystem.Threading.Tasks.dll 以选择它们。
      6. 点击添加按钮上的小下拉箭头。 (不要点击添加按钮。)
      7. 添加按钮的下拉菜单中,点击添加为链接。这两个程序集现在都在项目的根目录中可见。
        • 您必须将程序集链接保留在项目的根目录中。不要将它们移动到子文件夹中。
        • 如果您的项目受源代码控制,那么您可能会注意到这些链接文件被标记为已排除(如果不是,它们应该是。) NuGet packages 文件夹,其中这些文件驻留,不应签入源代码管理。由于它们只是链接文件,因此任何人在还原其 NuGet 包后拉下您的更改都应该没有问题。
    4. 在解决方案资源管理器中选择两个链接的程序集文件(Ctrl + 左键单击)或简单地分别对每个文件执行以下步骤。
    5. 用鼠标右键单击任一选定文件并选择属性属性窗口打开。
    6. 复制到输出目录字段设置为如果更新则复制

    您的单元测试项目文件现在应该包含类似于以下内容的内容。

    <ItemGroup>
      <Content Include="..\..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll">
        <Link>System.Runtime.dll</Link>
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>
      <Content Include="..\..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll">
        <Link>System.Threading.Tasks.dll</Link>
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
    

    就是这样!

    请记住,您的单元测试项目以 .NET 4.5(或更高版本,如果您愿意)为目标,因此单元测试可以使用 async 方法和任何其他 .NET 4.5 功能。与您正在测试的 .NET 4.0 程序集不应该有任何冲突,但如果您确实发现了冲突,可能是因为您为较新的 Framework/C# 功能重新定义了某些类型并将它们公开,因此在您尝试在单元测试中使用这些相同的类型。最好的解决方案是简单地将这些类型设置为您正在测试的项目的内部。

    编辑:
    完成这些步骤后,您可能会收到一些构建警告:

    所有引用 My.csproj 的项目都必须安装 nuget 包 Microsoft.Bcl.Build。如需更多信息,请参阅http://go.microsoft.com/fwlink/?LinkID=317569
    {root}\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets

    为避免这些警告,只需编辑 单元测试项目 并将以下元数据元素添加到每个项目引用中,该引用指向引用 Microsoft.Bcl.Build 的项目.

    <Properties>SkipValidatePackageReferences=true</Properties>
    

    例如:

    <ProjectReference Include="..\pcl\pcl.csproj">
      <Project>{664a9e98-fac7-4567-a046-0dde95fddb48}</Project>
      <Name>pcl</Name>
      <Properties>SkipValidatePackageReferences=true</Properties>
    </ProjectReference>
    

    完整的解释可以在 Microsoft.Bcl.Build 包中注明的 .targets 文件中找到。为了您的方便,这是完整的评论。

    BclBuildValidateNugetPackageReferences

    此目标验证当前项目中安装的任何 Nuget 包也安装在项目中 引用当前项目。

    这是必要的,因为 Nuget 包包含的不仅仅是简单的引用。安装包确保
    1. 添加了目标框架的正确引用集
    2. 应用配置文件转换
    3.项目安装脚本运行

    对于在 packages config 中列出的为当前项目安装的所有包,如果包 ID 与 @(ValidatePackages) 中指定的匹配,请确保在引用项目中安装相同的包。

    可以通过为参考设置 SkipValidatePackageReferences=true 来为项目参考禁用此目标:

    <ProjectReference Include="..\pcl\pcl.csproj">
      <Project>{664a9e98-fac7-4567-a046-0dde95fddb48}</Project>
      <Name>pcl</Name>
      <Properties>SkipValidatePackageReferences=true</Properties>
    </ProjectReference>
    

    可以通过添加以下内容来禁用对项目的所有引用的此目标:

    <PropertyGroup>
      <SkipValidatePackageReferences>true</SkipValidatePackageReferences>
    </PropertyGroup>
    

    【讨论】:

      最近更新 更多