HomeContact

InternalsVisibleTo Exposing Internal Members to Test Projects in .NET

By Shady Nagy
Published in dotnet
March 13, 2025
2 min read
InternalsVisibleTo Exposing Internal Members to Test Projects in .NET

InternalsVisibleTo: Exposing Internal Members to Test Projects in .NET

The Problem

When building .NET applications following clean architecture principles, we often want to encapsulate certain classes or members as internal to prevent them from being accessed outside their assembly. This approach is great for maintaining proper encapsulation and hiding implementation details.

However, this creates a challenge when writing unit tests. How do we test these internal members if they’re not accessible from our test project?

Consider this scenario:

// In your main project
internal class PolicyEnforcer
{
internal bool ValidatePolicy(string policyName)
{
// Implementation details
return true;
}
}

If we try to access this class from our test project:

// In your test project
[Fact]
public void ValidatePolicy_ShouldReturnTrue_ForValidPolicy()
{
// Error: PolicyEnforcer is inaccessible due to its protection level
var enforcer = new PolicyEnforcer();
// Error: ValidatePolicy is inaccessible due to its protection level
bool result = enforcer.ValidatePolicy("AdminPolicy");
Assert.True(result);
}

This code won’t compile because the PolicyEnforcer class and its methods are internal and not accessible to the test project.

The Solution: InternalsVisibleTo

.NET provides the InternalsVisibleTo attribute which allows you to expose internal members to specific assemblies, such as your test project.

Here’s how to implement it in your project file (.csproj):

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>EntityFrameworkCore.PolicyEnforcement.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

This configuration tells the compiler to make all internal members visible to the specified assembly EntityFrameworkCore.PolicyEnforcement.Tests.

Step-by-Step Implementation

  1. Open your project file (.csproj) of the assembly containing the internal members:

    # Navigate to your project directory
    cd YourProject
    # Open the project file with your preferred editor
    code EntityFrameworkCore.PolicyEnforcement.csproj
  2. Add the InternalsVisibleTo attribute within an ItemGroup element:

    <ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
    <_Parameter1>EntityFrameworkCore.PolicyEnforcement.Tests</_Parameter1>
    </AssemblyAttribute>
    </ItemGroup>
  3. Save the project file and rebuild your solution.

  4. Verify access by writing a test that accesses the internal members:

    // In EntityFrameworkCore.PolicyEnforcement.Tests project
    [Fact]
    public void ValidatePolicy_ShouldReturnTrue_ForValidPolicy()
    {
    // Now this works!
    var enforcer = new PolicyEnforcer();
    bool result = enforcer.ValidatePolicy("AdminPolicy");
    Assert.True(result);
    }

Alternative Approach using Assembly-Level Attribute

Instead of adding the attribute to your project file, you can also add it directly in code:

// Add this to any .cs file in your main project (e.g., AssemblyInfo.cs)
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("EntityFrameworkCore.PolicyEnforcement.Tests")]

Benefits

  1. Maintain Encapsulation: Keep your implementation details hidden from consumers of your library or application while still being able to test them.

  2. Better API Design: You can design a clean public API while still having the ability to test internal implementation details.

  3. Improved Security: Prevent unauthorized access to sensitive components or algorithms without sacrificing testability.

  4. Simplified Testing: Test internal members directly without having to expose them through public interfaces purely for testing purposes.

  5. Support for Clean Architecture: Maintain proper domain boundaries while still ensuring all components are testable.

Considerations and Best Practices

  1. Be Specific with Assembly Names: Make sure the assembly name specified in the InternalsVisibleTo attribute exactly matches your test project’s assembly name.

  2. Strong-Named Assemblies: If your assembly is strong-named, you’ll need to include the public key in the InternalsVisibleTo attribute.

  3. Keep It Limited: Only expose internals to test assemblies, not to production code.

  4. Document Usage: Add comments explaining why certain classes or members are internal and how they should be tested.

  5. Avoid Implementation Coupling: Even though you can test internal members, try to design your tests to focus on behavior rather than implementation details where possible.

Conclusion

The InternalsVisibleTo attribute is a powerful tool in the .NET developer’s toolkit that enables you to maintain proper encapsulation while ensuring your code remains testable. By carefully exposing internal members to your test projects, you can achieve the best of both worlds: clean architecture with strong encapsulation and comprehensive test coverage.

For .NET 8 and EF Core projects, this technique is particularly valuable when you’re working with repositories, specifications, and domain-driven design patterns where maintaining proper boundaries is essential to the architecture’s integrity.

By adding a simple XML snippet to your project file, you can significantly improve your ability to test internal components without compromising your application’s design principles.

Feedback and Questions

Your insights drive us! For any questions, feedback, or thoughts, feel free to connect:

  1. Email: shady@shadynagy.com
  2. Twitter: @ShadyNagy_
  3. LinkedIn: Shady Nagy
  4. GitHub: ShadyNagy

If you found this guide beneficial, don’t hesitate to share it with your network. Until the next guide, happy coding!


Tags

.NET Coredotnet.NET 8

Share


Previous Article
Setting Up Samba on Proxmox A Detailed Guide
Shady Nagy

Shady Nagy

Software Innovation Architect

Topics

AI
Angular
dotnet
GatsbyJS
Github
Linux
MS SQL
Oracle

Related Posts

Using the Factory Design Pattern in a .NET 8 API
Using the Factory Design Pattern in a .NET 8 API
October 13, 2024
2 min

Quick Links

Contact Us

Social Media