Globally applying InternalsVisibleTo across multiple .NET projects
I recently stumbled across a nice generic way to apply the InternalsVisibleTo assembly attribute automatically to all class libraries in my solution.
Adding "InternalsVisibleTo" attributes in project files
I've long used the following snippet in my .csproj
class library project files to expose internal
classes to unit test projects. The use of the $(AssemblyName)
variable makes this a reusable snippet that can be copy/pasted into new projects without modification.
I won't get into the caveats of testing internals of class libraries here. It's something that requires careful judgement to ensure that you are testing at the right level of abstraction - but that's a topic for another article.
I recently realised there is an easier way to achieve this in solutions with multiple class libraries that all need the same attributes. To do so we can simply place the above snippet in a Directory.Build.props file.
Directory.Build.props
I have a love/hate relationship with Microsoft's MSBuild ecosystem and its slightly archaic markup and hierarchies of inherited build targets/properties.
As a result, I haven't always made the most of useful available conventions like Directory.Build.props
files.
If you're new to this concept, Directory.Build.props
files allow you to apply MSBuild properties and common build configuration at a directory level, to multiple projects. They're automatically discovered and applied at build time just by virtue of being present on disk.
So let's say we have a solution structure like this:
The examples in this article use my conventions of naming unit test projects with .Tests
and .IntegrationTests
suffixes. You can obviously tweak the provided examples to suit any project naming conventions you might have.
To automatically make internals visible to corresponding unit/integration test projects in the solution - without requiring configuration on a per-project basis - we just need to add the following Directory.Build.props
file in the src
folder:
This will be applied to all .csproj
projects in src/
including any new class libraries added in the future.
Note: The filename Directory.Build.props
is case-sensitive. This initially caught me out because I had used a lower case "B" in the filename which worked fine on my case-insensitive Mac but failed to work in my case-sensitive Linux GitHub Actions runners.