Unit Testing y acceso a clases declaradas como internal (I)
Cuando desarrollamos nuestras aplicaciones, podemos encontrarnos con la necesidad de crear clases de tipo interno que sólo sean accesibles a través de la propia clase que las crea.
Supongamos el siguiente ejemplo en el que tenemos una biblioteca de clases con dos clases, una de ellas internal, y otra pública que podrá ser accedida por otro proyecto que referencie a nuestra clase.
namespace InternalSampleClass { internal class InternalClass { public string Get() { return $"{nameof(InternalClass)} from {nameof(Get)}"; } } }
namespace InternalSampleClass { public class ClassFoo { public string MyFunction() { var otherClass = new InternalClass(); return $"{nameof(MyFunction)} => {otherClass.Get()}"; } } }
Ahora creemos una aplicación de consola que referencie a nuestra biblioteca de clases e intentemos acceder a la clase pública y a la clase internal.
Indudablemente, a la clase pública podremos acceder de forma directa.
Sin embargo, a la clase marcada como internal no, tal y como podemos apreciar en la siguiente imagen:
Ahora, extrapolemos la aplicación de consola por un proyecto de Tests con xUnit por ejemplo.
El problema no dejará de desaparecer aunque creemos un proyecto de tests.
El hecho de que accedamos desde la aplicación de consola a una clase declarada como internal no tiene mucho sentido, ya que si la hemos declarado como internal es para que sólo sea accedida dentro del ámbito de la librería en la que se declara.
Sin embargo, cuando queremos crear nuestro proyecto de pruebas, parece cobrar sentido que podamos acceder a las clases internal para por lo menos asegurarnos que se entregan con cierta calidad.
Pero hemos dicho que no podemos acceder a ellas, así que la pregunta obligada que debemos hacernos entonces es: ¿cómo resolver el problema de acceder a una clase internal?.
.NET nos ofrece un mecanismo para resolver este problema, y es el de ir a nuestra biblioteca de clases e indicar allí qué ensamblado puede ver las clases internal como sino lo fueran.
Para ello, basta con ir al proyecto de la biblioteca de clases que contiene las clases internal, y abrir el fichero AssemblyInfo.cs agregando (al final o donde quieras) algo parecido a esto (en mi caso):
[assembly: InternalsVisibleTo(«InternalTests»)]
Lógicamente, donde pongo «InternalTests» deberemos indicar el nombre de nuestro ensamblado de pruebas unitarias (o incluso el ensamblado o librería que queramos que tenga acceso a nuestras clases internal si se diera el caso).
De esta manera, mi proyecto de tests llamada InternalTests tendrá acceso a las clases internal como podemos ver en la siguiente imagen:
Haciéndolo así, podremos acceder desde nuestro proyecto de pruebas unitarias a estas clases como si no fueran internas y asegurar su correcto y esperado funcionamiento.
No obstante, también existe una alternativa adicional a añadir en AssemblyInfo.cs el proyecto en el que queremos hacer visible las clases internal, y es añadir en el mismo código fuente y en el lugar en el que se declaran los using de la misma clase internal algo parecido a esto:
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo(«InternalTests»)]
El resultado será el mismo que hemos visto.
Happy Coding!