
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 projectinternal class PolicyEnforcer{internal bool ValidatePolicy(string policyName){// Implementation detailsreturn 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 levelvar enforcer = new PolicyEnforcer();// Error: ValidatePolicy is inaccessible due to its protection levelbool 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.
.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
.
Open your project file (.csproj) of the assembly containing the internal members:
# Navigate to your project directorycd YourProject# Open the project file with your preferred editorcode EntityFrameworkCore.PolicyEnforcement.csproj
Add the InternalsVisibleTo attribute within an ItemGroup
element:
<ItemGroup><AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute"><_Parameter1>EntityFrameworkCore.PolicyEnforcement.Tests</_Parameter1></AssemblyAttribute></ItemGroup>
Save the project file and rebuild your solution.
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);}
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")]
Maintain Encapsulation: Keep your implementation details hidden from consumers of your library or application while still being able to test them.
Better API Design: You can design a clean public API while still having the ability to test internal implementation details.
Improved Security: Prevent unauthorized access to sensitive components or algorithms without sacrificing testability.
Simplified Testing: Test internal members directly without having to expose them through public interfaces purely for testing purposes.
Support for Clean Architecture: Maintain proper domain boundaries while still ensuring all components are testable.
Be Specific with Assembly Names: Make sure the assembly name specified in the InternalsVisibleTo
attribute exactly matches your test project’s assembly name.
Strong-Named Assemblies: If your assembly is strong-named, you’ll need to include the public key in the InternalsVisibleTo
attribute.
Keep It Limited: Only expose internals to test assemblies, not to production code.
Document Usage: Add comments explaining why certain classes or members are internal and how they should be tested.
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.
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.
Your insights drive us! For any questions, feedback, or thoughts, feel free to connect:
If you found this guide beneficial, don’t hesitate to share it with your network. Until the next guide, happy coding!
Quick Links
Legal Stuff