TDD – Testing [internal] classes from an external project

by EvanJPalmer

TLDR:

In Visual Studio, to access a C# class marked as internal from an external project, add this line to your properties\AssemblyInfo.cs file:

[assembly: InternalsVisibleTo("NameOfProjectAsString")]

The longer version:

When I’m doing Test Driven Development I tend end up with a lot of classes – each with a single well defined responsibility and no external dependencies*. Usually I’d write each class with a public access modifier so they can be tested, even though in the majority of cases the class will only be used in this project, and internal access should suffice.

For example consider the following simplified case for a class that might be used in a NuGetPackage:

namespace MyNugetPackage.Logic
{
    public class SpecialStringFormatter
    {
        ValueRetreiver _valueRetreiver = new ValueRetreiver();
        ContextDeterminer _contextDeterminer = new ContextDeterminer();

        public string FormatTheString()
        {
            // DO Something
        }
    }

    public class ValueRetreiver
    {
        public int GetInt()
        {
            // DO Something
        }

        public string GetString()
        {
            // DO Something
        }
    }

    public class ContextDeterminer
    {
        public object DetermineTheContext(string username)
        {
            // DO Something
        }
    }
}

With the above example, when accessing it from a project that includes that NuGet package, you’ll get the following Intellisense:

IntellisenseExample1

In this example, the only time ValueRetreiver and ContextDeterminer are used is in SpecialStringFormatter so really they are just obfuscating the intent.

Usually this isn’t a big problem since the class will probably be used by team members who would would probably know what to use, but I’m currently working on a nuget package and and I want the usage of my package to be easily discoverable with Intellisense (which is proabably a noble goal for all your code anyway).

If I switch these to internal the Intellisense looks like this:

IntellisenseExample2

Much nicer, don’t you agree?

Now the problem is, that my classes aren’t visible to my testing project. The solution to this it to allow access to a different project via the attribute:

[assembly: InternalsVisibleTo("NameOfProjectAsString")]

which I added to my properties\AssemblyInfo.cs file.

I also needed to give access to my mocking frame work (Moq) with this attribute, including that very specific string:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

Do you know of a better way of achieving this?

* well, I try.

Advertisements