Friday 1 January 2016

How to use internal type as a unit test argument

Behavioral tests sometimes require access to types which are internal for the SUT assembly. If those types are used in test methods, test assembly name has to be specified through InternalsVisibleToAttribute in SUT assembly. For example, if MyAppTests is a library containing tests for classes within MyApp we have to do the following:
  • in MyAppTests: add the reference to MyApp so all public types are visible
  • in MyApp: specify MyAppTests as the assembly in which internal types are visible. The following line has to be added to MyApp/Properties/AssemblyInfo.cs:

[assembly: InternalsVisibleTo("MyAppTests")]

This makes internal types visible within unit tests. But if we want to pass such types as arguments to unit tests (via TestCase or TestCaseSource attributes), compiler will complain about inconsistent accessibility.

For example, if we have public class (SUT) and internal enum:

and the following test:

Compiler issues an error:

Error CS0051 Inconsistent accessibility: parameter type 'MyEnum' is less accessible than method 'MyClass_Tests.Foo_Does_This_When_MyEnum_Is_Value1_or_Value2(MyEnum)'

Unit test methods have to be public, otherwise unit test runners will not be able to see them or would report that test fails (Nunit Test Adapter also issues error message: "Method is not public"). Unit tests are public API so types of their arguments also have to be public (visible in any assembly, not just in test library).

The solution for this is to pass arguments to test method as type object and then cast them back to the original internal type:

In this particular case, when internal type is enum, we could gave passed type int instead of object but for any other custom internal type, object is the only solution.

Thread which explains reasons why NUnit fails but does not ignore non-public test methods.

No comments: