如何对 Moq 可见内部接口?

Posted

技术标签:

【中文标题】如何对 Moq 可见内部接口?【英文标题】:How to do internal interfaces visible for Moq? 【发布时间】:2015-03-29 20:08:10 【问题描述】:

我的 C# 解决方案中有 3 个项目。

签名 结构 测试

签名具有公共和内部接口。 此外,它有

  [assembly: InternalsVisibleTo("Structures")]
  [assembly: InternalsVisibleTo("Tests")]

在 AssemblyInfo.cs 中。

结构具有公共类和内部类,并且

  [assembly: InternalsVisibleTo("Tests")]

在 AssemblyInfo.cs 中。

Tests 有下一个来源:

<packages>
  <package id="Moq" version="4.2.1409.1722" targetFramework="net45" />
  <package id="NUnit" version="2.6.4" targetFramework="net45" />
  <package id="NUnitTestAdapter" version="1.2" targetFramework="net45" />
</packages>

作为 packages.config 中的 NuGet 包。

我为 Signatures 的内部接口和 Structures 的内部类编写了一个单元测试。运行,得到下一个结果:异常:

类型 Signatures.InterfaceX 对 DynamicProxy 不可见。无法为不可访问的类型创建代理。将类型设为 public 或 internal 并使用 [assembly: InternalsVisibleTo(InternalsVisible.ToDynamicProxyGenAssembly2)] 属性标记您的程序集。

似乎合乎逻辑。我加了

[assembly: InternalsVisibleTo("InternalsVisible.DynamicProxyGenAssembly2")] 

到签名和结构项目的装配信息。运行,得到下一个结果:异常:

程序集“DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”中的类型“Castle.Proxies.IReminiscenceableDataTableProxy”正在尝试实现无法访问的接口。

我希望它会有所帮助,但它没有。 它只是更改了异常消息。

如何解决我的问题?

【问题讨论】:

【参考方案1】:

将以下内容添加到定义类的项目中的 csproj 文件中。

<ItemGroup>
    <!-- For Moq to mock internal class objects -->
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
      <_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
    </AssemblyAttribute>
  </ItemGroup>

【讨论】:

【参考方案2】:

在 .Net Core / .NET 5 中,您还可以将用户 DanKodi 的答案与 this 文章结合起来,因此您无需在任何地方设置 assembly 属性。

只需编辑包含您要测试的代码的生产代码 .proj 文件,如下所示:

<ItemGroup>

    <!-- Make assembly visible to test assembly -->
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(AssemblyName).Tests</_Parameter1>
    </AssemblyAttribute>

    <!-- Make assembly usable for Moq, so Moq is able to instanciate objects of 'internal' classes -->
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
        <_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
    </AssemblyAttribute>

</ItemGroup>
这将执行以下操作: 它使程序集对包含测试的项目可见(如 只要测试项目的名字是你想要的项目的名字 使用“.Tests”后缀进行测试) 它使 mock 能够实例化该项目的内部类

【讨论】:

【参考方案3】:

建议的修复消息使用 const/static 字段作为程序集名称:

[assembly: InternalsVisibleTo(InternalsVisible.ToDynamicProxyGenAssembly2)]

您使用了与程序集名称不对应的字符串:

[assembly: InternalsVisibleTo("InternalsVisible.DynamicProxyGenAssembly2")] 

改成:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] 

您可以在错误消息中看到实际的程序集名称(应该出现在 InternalsVisibleTo 中):

从程序集“DynamicProxyGenAssembly2 (...) 中键入“Castle.Proxies.IReminiscenceableDataTableProxy”(...)

【讨论】:

这是一个重要的区别。抛出的错误消息让人认为我们需要第二个选项,但第三个实际上修复了它。 Castle Project 似乎暴露了一个 const 成员,就像消息中的那个一样,请参阅 Castle.Core/Core/Internal/InternalsVisible.cs,但似乎由于 Castle Project 嵌入在 Moq.dll 中的方式,这当通过 Moq 查看时,类变为非公开的,并且因为它不可访问,所以说 [assembly: InternalsVisibleTo(Castle.Core.Internal.InternalsVisible.ToDynamicProxyGenAssembly2)] 将不起作用。所以你必须拥有自己的魔线。 这对我不起作用,说强名称签名的程序集但包含公钥 此外,不可能对上述程序集进行混淆,所以 IMO 不是很好。

以上是关于如何对 Moq 可见内部接口?的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin:使内部函数对单元测试可见

csharp C# - 使内部方法对其他程序集可见

GCC:内部可见性“在现实世界的使用中毫无用处”?

内部类

零基础学Java—内部类的概念与分类(三十)

海湾合作委员会:可见度内部以什么方式“在实际使用中相当无用”?