2008-10-05 17 views
24

Estoy intentando probar la unidad de una clase que tiene muchas funciones internas. Obviamente, estos también necesitan pruebas, pero mi proyecto de Pruebas es independiente, principalmente porque cubre muchos proyectos pequeños y relacionados. Lo que tengo hasta ahora es:¿Cómo acceder a miembros internos a través de System.Reflection?

FieldInfo[] _fields = 
    typeof(ButtonedForm.TitleButton).GetFields(
     BindingFlags.NonPublic | BindingFlags.Instance | 
     BindingFlags.DeclaredOnly); 
Console.WriteLine("{0} fields:", _fields.Length); 
foreach (FieldInfo fi in _fields) 
{ 
    Console.WriteLine(fi.Name); 
} 

Este escupe todos los miembros privados muy bien, pero todavía no muestra componentes internos. Sé que esto es posible, porque cuando estaba jugando con las pruebas autogeneradas que Visual Studio puede producir, me preguntó sobre qué hacer al mostrar las partes internas del proyecto de prueba. Bueno, ahora estoy usando NUnit y realmente me gusta, pero ¿cómo puedo lograr lo mismo con eso?

Respuesta

32

Sería más apropiado utilizar el atributo InternalsVisibleTo para otorgar acceso a los miembros internos del conjunto al conjunto de prueba de la unidad.

Aquí hay un enlace con algo de información adicional útil y un paseo a través de:

Para responder a su pregunta en realidad ... interna y protegida, no se reconocen en la reflexión .NET API. Aquí es una cita de MSDN:

El C# palabras clave protegida e interna no tienen ningún significado en IL y no se utilizan en las API de reflexión. Los términos correspondientes en IL son Familia y Asamblea. Para identificar un método interno usando Reflection, use la propiedad IsAssembly. Para identificar un método interno protegido, use el IsFamilyOrAssembly.

+0

Estoy de acuerdo con el uso de InternalsVisibleTo, pero también agradezco la respuesta :) –

+0

No hay problema, es bueno tener una explicación real, incluso si en su caso de uso particular, un enfoque diferente es más apropiado. –

+2

Sólo un FYI, la página vinculada a esta respuesta es mía y mi URL ha cambiado. Es por eso que podría obtener un 404. Pruebe este enlace actualizado http://jason.whitehorn.ws/2007/11/09/The-Wonders-Of-InternalsVisibleTo.aspx –

6

Agregando el atributo de nivel de ensamblaje InternalsVisibleTo a su proyecto principal, con el nombre de conjunto del proyecto de prueba debe hacer visibles los miembros internos.

Por ejemplo añadir lo siguiente a su ensamblaje fuera de cualquier clase:

[assembly: InternalsVisibleTo("AssemblyB")] 

O para una orientación más específica:

[assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")] 

Nota, si el conjunto de aplicación tiene un nombre seguro, su prueba el ensamble también necesitará ser fuertemente nombrado.

6

Creo que debe preguntar si debe escribir pruebas unitarias para métodos privados? Si escribe pruebas unitarias para sus métodos públicos, con una cobertura de código 'razonable', ¿no está probando ya algún método privado que deba llamarse como resultado?

Las pruebas de vinculación a métodos privados harán que las pruebas sean más frágiles. Debería poder cambiar la implementación de cualquier método privado sin romper ninguna prueba.

Refs:

http://weblogs.asp.net/tgraham/archive/2003/12/31/46984.aspx http://richardsbraindump.blogspot.com/2008/08/should-i-unit-test-private-methods.html http://junit.sourceforge.net/doc/faq/faq.htm#tests_11 http://geekswithblogs.net/geekusconlivus/archive/2006/07/13/85088.aspx

+0

¿Qué sucede cuando se produce un error en estas funciones más pequeñas y de repente dejan de pasar 10 pruebas? –

+0

Depende de la situación, supongo, pero ¿no sería simplemente más fácil de usar, por ejemplo, la sugerencia de InternalsVisibleTo, para exponerlos y escribir pruebas más específicas? –

+0

Pruebo todos mis métodos internos. Lo único que puede pasar con las pruebas es perder un poco de tiempo. –

6

Su código sólo muestra los campos - así que yo espero que no se muestran los miembros internos, como campos siempre deben ser privados de la OMI. (Con la posible excepción de las constantes.)

¿ButtonedForm.TitleButton en realidad tiene campos no privados? Si está tratando de encontrar los métodos internos , entonces obviamente necesita llamar al GetMethods (o GetMembers) para obtenerlos.

Como han sugerido otros, InternalsVisibleTo es muy útil para probar (¡y casi exclusivamente para probar!). En cuanto a si debe probar los métodos internos, ciertamente me parece útil poder hacerlo. No considero que las pruebas unitarias sean exclusivamente pruebas de caja negra. A menudo, cuando usted sabe que la funcionalidad pública se implementa utilizando unos pocos métodos internos conectados de una manera simple, es más fácil hacer pruebas exhaustivas de cada uno de los métodos internos y algunas pruebas de "pseudointegración" en el método público.

+0

Tienes razón, debería haber estado llamando GetMethods() de todos modos para empezar. +1 mañana cuando obtenga más votos de nuevo. Soy nuevo en todo lo de la reflexión, ¿puedes decirlo? : D Tengo un pequeño lenguaje de scripting en proceso en algún momento, me imagino que voy a ponerme al tanto de la reflexión bien y verdaderamente ... –

1

Una justificación para usar el InternalsVisible es bajo mis circunstancias. Compramos el código fuente a un control de gráfico. Hemos encontrado dónde tenemos que hacer algunas modificaciones a ese control de fuente y compilar nuestra propia versión. Ahora, para asegurarnos de no romper nada, hay algunas pruebas de unidad que necesito escribir que necesitan acceso a algunos campos internos.

Este es un caso perfecto donde el InternalsVisible tiene sentido.

Me preguntaba, sin embargo, ¿qué harías si no tienes acceso a la fuente? ¿Cómo puedes llegar a un campo interno? .Net Reflector puede ver ese código, pero supongo que solo está mirando el IL.

+0

Como alguien más mencionó, en IL las estructuras internas se llaman Ensamblaje. Puede usar System.Reflection para acceder a estas variables de ensamblaje –

Cuestiones relacionadas