Double-edged sword of InternalsVisibleTo


This post was originally published here.

I’ve had some conversations with both Joe and Elton lately about the InternalsVisibleTo attribute.  From the documentation, the assembly-level InternalsVisibleTo attribute:

Specifies that all nonpublic types in an assembly are visible to another assembly.

This attribute was introduced in C# 2.0, and allows you to specify other assemblies that can see all types and members marked “internal”.  In practice, all assemblies are signed with the same public key, and you’d specify that the unit test assembly can see that assembly.

  • MyProject.Core -> has the “InternalsVisibleTo” attribute defined in the AssemblyInfo.cs file, pointing at the below assembly
    • MyProject.Core.Tests -> is signed with the same public key as the Core assembly</ul> Notice that the “Core” project knows about the “Tests” project, but the actual project dependency is the other way around.  It’s definitely better than using reflection to access private members for testing, but there are some definite pros and cons with this approach.

    Pros

    • Allows your test libraries to access internal classes and methods for additional testing and coverage
      • Keeps your public API limited to what you want to publish
        • Provides greater flexibility for internal refactoring and backwards compatibility
          • Reduces the surface area of your public API</ul>

            Cons

          • Easily abused, so things usually marked “private” are now marked “internal”
            • Potential loss of encapsulation
              • Decision about what should be public could be wrong
                • Essentially two levels of “public” visibility that have to be managed
                  • Enforces bi-directional dependencies between assemblies</ul> Personally, I always felt like marking something “internal” was cheating just a little bit, and I have trouble deciding when to make something internal or not.  But unless you’re delivering a public, published and documented API as part of your product, using the “InternalsVisibleTo” attribute would probably be overkill.

                  However, if you are delivering an API, you should consider using this attribute to keep a high level of coverage and reduce the surface area the API for your customers.  You could try starting by making everything “internal”, then shape the public API based on specific use cases.

Dialing up quality