.net unit-testing language-agnostic friend internalsvisibleto

.net - Usar declaraciones de "amigo" para pruebas unitarias. ¿Mala idea?



unit-testing language-agnostic (5)

[ Por supuesto, la pregunta no está restringida a una implementación específica de "amigo"; sin embargo, siéntase libre de señalar aspectos específicos de la implementación, si corresponde ]

Al leer las preguntas sin respuesta, me encontré con el atributo InternalsVisibleTo :

Especifica que los tipos que son normalmente visibles solo dentro del ensamblaje actual son visibles para otro ensamblaje.

La Guía de programación de C # en MSDN tiene una sección Conjuntos de amigos que describe cómo usar el atributo para permitir el uso de métodos y tipos internal a otro ensamblaje.

Me pregunto si sería una buena idea usar esto para crear una interfaz "oculta" para instrumentar una biblioteca para que la utilice el ensamblaje de prueba de la unidad. Parece aumentar el acoplamiento de forma masiva en ambas direcciones (código de prueba en el conjunto de producción, conocimiento interno íntimo sobre el ensamblaje de producción en el código de prueba), pero por otro lado podría ayudar a crear pruebas detalladas sin saturar la interfaz pública.

¿Cuál es su experiencia con el uso de declaraciones de amigos al realizar pruebas? ¿Fue su Silver Bullet o comenzó la Marcha de la Muerte?


Es el único uso que he aplicado personalmente a InternalsVisibleTo , y ha sido muy, muy útil.

No veo las pruebas unitarias como pruebas de caja negra, ya están unidas a la implementación en cierta medida. Ser capaz de probar métodos y tipos internos permite un enfoque mucho más ajustado (unidades más pequeñas).


He hecho un uso extenso de esta técnica, esto significa que mis pruebas unitarias pueden probar aspectos de la biblioteca de códigos que no son visibles para los consumidores normales.

Si bien el uso de [InternalsVisibleTo] aumenta el acoplamiento, creo que el aumento (menor) bien vale las ganancias.

Las pruebas de mi unidad ya están estrechamente vinculadas con el código bajo prueba, aunque intento escribir pruebas que aseguren resultados específicos, no implementaciones específicas, al acceder a cosas que no son visibles para los consumidores habituales, de alguna forma limito la implementación.

Yendo para otro lado, el acoplamiento es mínimo: tener el atributo [InternalsVisibleTo] en el ensamblaje del código y marcar algunas cosas como internas en lugar de privadas (o internas protegidas en lugar de protegidas ).

(Tenga en cuenta que ignoro aquí cualquier cambio en el diseño provocado por el uso de Unit Testing, que es una discusión completamente diferente).

El atributo [InternalsVisibleTo] requiere un fuerte nombre para sus ensamblajes. Si aún no lo hace, puede encontrar esto un poco oneroso ya que un ensamble con un nombre fuerte solo puede depender de otros ensamblajes fuertemente nombrados, lo que puede terminar con la necesidad de modificar varios ensamblajes.

Obtener el atributo correcto puede ser un poco complicado, ya que debe incluir la clave pública de su ensamblaje de prueba. IDesign tiene una útil herramienta de ensamblaje de amigos que crea el atributo en su portapapeles, listo para pegar. Recomendado.


De hecho, Unit Testing es el único uso que he podido hacer para usar InternalsVisibleToAttribute for. Con esto, puede implementar una gran parte de sus métodos "privados" como internos para exponerlos al marco de pruebas de la unidad para realizar pruebas más invasivas de invariantes internos de clase.

He tenido un gran éxito con esta técnica. Si nada más lo ayuda a abordar ese mítico objetivo de cobertura de código al 100% al permitirle invocar métodos privados en situaciones que de otro modo serían inaccesibles.


Creo que aparece otro caso de uso legítimo cuando se utilizan ensamblajes separados cuando se combina el código de C ++ heredado con el código de C # más nuevo.

Tomamos los ensamblajes de C ++, los convertimos en C ++ / CLI y luego implementamos el código más nuevo en C #. Cuando hagamos esto, aún usaríamos "interno" para las clases / métodos en C # que no son realmente públicos, y luego los pondremos a disposición del código heredado como ensamblajes amigos.


Creo que usar InternalsVisibleToAttribute para habilitar las pruebas unitarias es perfectamente razonable. Mi "unidad" en "pruebas unitarias" es una clase, y eso incluye clases internal , por lo que quiero probarlas. Sin embargo, no quiero probar private métodos private .

No creo que sea una buena idea crear una interfaz especial y privada solo para pruebas. Uno de los valores de las pruebas unitarias es que le da la oportunidad de pensar en la interfaz de su clase desde el punto de vista de un consumidor de esa clase; proporcionar una puerta trasera le quita ese beneficio.

Mi preferencia, sin embargo, es poner mis pruebas unitarias en el mismo ensamblaje que mi código de producción. Por lo general, no afecta a mi cliente, pero me simplifica las cosas, así que lo hago. Cuando lo hago, hace que la pregunta de InternalsVisibleTo desaparezca.