VS2017 .NET Standard 库中的单元测试内部方法

Unit testing internal methods in VS2017 .NET Standard library

我目前正在通过创建 .NET Standard 1.6 库来使用最新的 Visual Studio 2017 Release Candidate。我正在使用 xUnit 对我的代码进行单元测试,想知道您是否仍然可以在 VS2017 中测试内部方法。

我记得你可以在 VS2015 中的 AssemblyInfo.cs class 中添加一行,使指定的项目能够看到内部方法:

[assembly:InternalsVisibleTo("MyTests")]

由于 VS2017 .NET Standard 项目中没有 AssemblyInfo.cs class,我想知道您是否仍然可以对内部方法进行单元测试?

根据.NET docs for the InternalsVisibleToAttribute

The attribute is applied at the assembly level. This means that it can be included at the beginning of a source code file, or it can be included in the AssemblyInfo file in a Visual Studio project.

换句话说,您只需将它放在您自己任意命名的 .cs 文件中,它应该可以正常工作:

// some .cs file included in your project
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]

"InternalsVisibleTo" 属性是任何类型的 "white-box"(我猜是十年的术语)测试 .Net 的关键。它可以放在前面带有 "assembly" 属性的任何 c# 文件中。请注意,MS DOC 指出程序集名称必须由 public 密钥标记限定(如果已签名)。有时这不起作用,必须在其位置使用完整的 public 键。访问内部是测试并发系统和许多其他情况的关键。参见 https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054。在本书中,Meszaros 描述了各种编码风格,这些风格基本上构成了程序开发的 "Design For Test" 方法。至少那是我多年来使用它的方式。

添加: 抱歉,我有一段时间没来这里了。一种方法被 Meszaros 称为 "testing subclass" 方法。同样,必须使用 "internalsvisableto" 才能访问基础 class 的内部结构。这是一个很好的解决方案,但它不适用于密封的 classes。当我教 "Design For Test" 时,我建议它是 "pre-engineered" 到基础 classes 中所需要的东西之一,以提供可测试性。它几乎必须成为一种文化。设计一个未密封的 "base" 底座 class。将其称为 UnsealedBaseClass 或统一可识别的名称。这是 class 将被 subclass 编辑以进行测试。它也是 subclassed 来构建密封的产品 class,它通常只在它公开的构造函数上有所不同。我在核工业工作,并且非常重视测试要求。所以,我不得不时刻考虑这些事情。顺便说一句,在我们的领域中,在生产代码中保留测试挂钩不被视为问题,只要它们在 .Net 实现中 "internal" 即可。不测试某些东西的后果可能非常深远。

虽然第一个答案非常好。如果你觉得你仍然想在原来的 AssemblyInfo 中这样做,你可以随时选择不自动生成文件并手动添加它。

<PropertyGroup>
   <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>

更多信息:

另一种方法是在目标项目中使用 'wrapper' TestMyFoo public class,它具有 public 方法并继承自您需要的 class测试(例如 MyFoo)。这些 public 方法只是调用您要测试的基础 class。

它不是 'ideal',因为您最终在目标项目中发布了一个测试挂钩。但是请考虑带有诊断端口的现代可靠汽车和带有 JTAG 连接的现代可靠电子产品。但是没有人傻到用诊断端口来开车。

如此处所述:

https://blog.sanderaernouts.com/make-internals-visible-with-new-csproj-format

可以通过添加另一个 ItemGroup 在项目文件中添加内部可见属性:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(AssemblyName).Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

甚至:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(MSBuildProjectName).Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

我喜欢这个解决方案,因为项目文件似乎是定义此类问题的正确位置。