Last year I blogged about the inner workings of private method testing features
in Visual Studio .NET 2005 Team System. As regular readers might
recall, VSTS generates accessor classes which again use reflection to
access the targets internals. I recently discovered that there is
another way to expose internals to other classes in .NET 2.0 called
Friend Assemblies. An assembly can make friends with other assemblies
in a declarative fashion using the new InternalsVisibleTo
attributes. With this attribute you can make all types with an assembly
accessible to one or more client assemblies. The attribute can only be
declared at assembly level. Below is an example of a declaration:
// ServerAssembly.cs
[assembly: InternalsVisibleTo("ClientAssembly")]
Client assemblies must be specifically granted
access to an assembly’s internals. In the above example, only
“ClientAssembly” is granted access assemblies that reference
“ClientAssembly” won’t be granted access to the server assembly’s
internals. The friendship is not mutal, while “ClientAssembly” is
allowed access to “ServerAssembly’s” internals, “ServerAssembly” is not
allowed access to “ClientAssembly’s” internals.
If you’re proficient .NETs security attributes you might recollect the StrongNameIdentityPermission
attribute. You can protect types with this attributes to ensure that
the calling code is a particular strong-named assembly. The StrongNameIdentityPermission can be applied to methods, constructors, structs, classes and assemblies allowing fine grained usage permission control. The InternalsVisibleTo
attribute on the other hand lets you expose an entire assembly with one
single declaration which is less time consuming and easier to manage.
However, there is another facet to using the InternalsVisibleTo instead of StrongNameIdentityPermission, When using the StrongNameIdentityPermission all the types you want to expose must be public to be visible to other assemblies, while the InternalsVisibleTo
attribute allows types to stay internal and still be visible in another
assembly. To the developer using the types in the two separate
assemblies the assemblies appear as one.
Regular type visibility rules still apply when using the InternalsVisibleTo attribute, so only types declared as public, internal or protected internal are available to the friend assembly. Private members are not available.
When it comes to accessing private members the reflection pattern
used by VSTS private method testing is still the way to go. However,
many people consider accessing private members as a “bad” practice. The
internal modifier makes types or
members visible only within an assembly and in a sense it can be
regarded as a scoped public modifier. It can often make sense to write
unit tests for internal helper classes and similar. This is a form of glass box testing that should be more acceptable than private method testing.