Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do internal interfaces visible for Moq?

I have 3 projects in my C# solution.

  • Signatures
  • Structures
  • Tests

Signatures have public and internal interfaces. Also, it has

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

in AssemblyInfo.cs of.

Structures have public and internal classes and

  [assembly: InternalsVisibleTo("Tests")]

in AssemblyInfo.cs of.

Tests has next source:

<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>

as NuGet packages in packages.config.

I wrote an unit test for the internal interface from Signatures and internal class from Structures. Run, and had next result: exception:

Type Signatures.InterfaceX is not visible to DynamicProxy. Can not create proxy for types that are not accessible. Make the type public, or internal and mark your assembly with [assembly: InternalsVisibleTo(InternalsVisible.ToDynamicProxyGenAssembly2)] attribute.

Seems logical. I added

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

to assembly info of Signatures and Structures projects. Run, and had next result: exception:

Type 'Castle.Proxies.IReminiscenceableDataTableProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is attempting to implement an inaccessible interface.

I expected it would help but it didn't. It only changed the exception message.

How to fix my problem?

like image 830
Valentine Zakharenko Avatar asked Jan 30 '15 10:01

Valentine Zakharenko


3 Answers

The suggested fix message uses a const/static field for the assembly name:

[assembly: InternalsVisibleTo(InternalsVisible.ToDynamicProxyGenAssembly2)]

You used a string which does not correspond to the assembly name:

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

Change it to:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] 

You can see the actual assembly name (which should appear in InternalsVisibleTo) in your error message:

Type 'Castle.Proxies.IReminiscenceableDataTableProxy' from assembly 'DynamicProxyGenAssembly2 (...)

like image 185
k.m Avatar answered Nov 11 '22 20:11

k.m


Add the below to the the csproj file in the project where the classes are defined.

<ItemGroup>
    <!-- For Moq to mock internal class objects -->
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
      <_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
    </AssemblyAttribute>
  </ItemGroup>
like image 30
DanKodi Avatar answered Nov 11 '22 20:11

DanKodi


In .Net Core / .NET 5 you can also combine user DanKodi's answer with this article, so you do not need to set the assembly attribute anywhere.

Just edit the production code .proj file that contains the code you want to test like this:

<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>

This does the following:

  • It makes the assembly visible to the project that contains the tests (as long as the name of the test project is the name of the project you want to test with an ".Tests" suffix)
  • It enables Moq to instanciate internal classes of that project
like image 6
Martin Avatar answered Nov 11 '22 21:11

Martin