c# - test - ¿Cómo se prueban los métodos privados con NUnit?
unit test c# ejemplo (12)
Disculpa si esto no responde a la pregunta, pero soluciones como usar la reflexión, las declaraciones #if #endif o hacer que los métodos privados sean visibles no resuelven el problema. Puede haber varias razones para no hacer que los métodos privados sean visibles ... ¿qué ocurre si se trata de un código de producción y, por ejemplo, el equipo está escribiendo pruebas de unidad de forma retrospectiva?
Para el proyecto en el que estoy trabajando, solo MSTest (lamentablemente) parece tener una manera, usando accesadores, de probar los métodos privados de prueba.
Me pregunto cómo usar NUnit correctamente. Primero creé un Test-Project separado que usa mi proyecto principal como referencia. Pero en ese caso no puedo probar métodos privados. ¡Creo que necesito incluir mi código de prueba en mi código principal! - Esa no parece ser la forma correcta de hacerlo. (No me gusta la idea de enviar código con pruebas).
¿Cómo se prueban los métodos privados con NUnit?
El objetivo principal de las pruebas unitarias es probar los métodos públicos de una clase. Esos métodos públicos usarán esos métodos privados. Las pruebas unitarias probarán el comportamiento de lo que está disponible públicamente.
En teoría de Unit Testing, solo el contrato debe ser probado. es decir, solo miembros públicos de la clase. Pero en la práctica, el desarrollador generalmente quiere probar miembros internos. - y no está mal. Sí, va en contra de la teoría, pero en la práctica puede ser útil a veces.
Entonces, si realmente quieres probar miembros internos, puedes usar uno de estos enfoques:
- Haz que tu miembro sea público. En muchos libros, los autores sugieren este enfoque como simple
- Puede hacer que sus miembros sean internos y agregar InternalVisibleTo a assebly
- Puede hacer que los miembros de la clase estén protegidos y heredar su clase de prueba de su clase de prueba.
Ejemplo de código (pseudo código):
public class SomeClass
{
protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{
protected void SomeMethod2() {}
[Test]
public void SomeMethodTest() { SomeMethod2(); }
}
Es posible probar métodos privados declarando su conjunto de prueba como un conjunto amigo del conjunto de destino que está probando. Vea el siguiente enlace para más detalles:
http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx
Esto puede ser útil ya que separa principalmente el código de prueba de su código de producción. Nunca utilicé este método porque nunca lo he necesitado. Supongo que podría usarlo para probar y probar casos extremos de prueba que simplemente no puede replicar en su entorno de prueba para ver cómo lo maneja su código.
Sin embargo, como ya se dijo, realmente no debería necesitar probar métodos privados. Es más que probable que desee refactorizar su código en bloques de construcción más pequeños. Un consejo que podría ayudarlo cuando venga a refactorizar es tratar de pensar sobre el dominio con el que se relaciona su sistema y pensar en los objetos ''reales'' que habitan en este dominio. Sus objetos / clases en su sistema deberían relacionarse directamente con un objeto real que le permitirá aislar el comportamiento exacto que debe contener el objeto y también limitar las responsabilidades del objeto. Esto significará que está refactorizando lógicamente en lugar de simplemente hacer posible probar un método en particular; podrás probar el comportamiento de los objetos.
Si aún sientes la necesidad de realizar una prueba interna, es posible que también quieras considerar burlar tus pruebas, ya que es probable que quieras centrarte en una parte del código. La burla es donde se inyecta una dependencia de objetos en ella, pero los objetos inyectados no son los objetos "reales" o de producción. Son objetos ficticios con comportamiento codificado para facilitar el aislamiento de errores de comportamiento. Rhino.Mocks es un popular marco de burla gratuito que esencialmente escribirá los objetos por ti. TypeMock.NET (un producto comercial con una edición de comunidad disponible) es un marco más poderoso que puede simular objetos CLR. Muy útil para burlarse de las clases SqlConnection / SqlCommand y Datatable, por ejemplo, cuando se prueba una aplicación de base de datos.
Es de esperar que esta respuesta le brinde un poco más de información para informarle acerca de las pruebas unitarias en general y para ayudarlo a obtener mejores resultados de las pruebas unitarias.
Esta pregunta está en sus años avanzados, pero pensé que compartiría mi forma de hacer esto.
Básicamente, tengo todas mis clases de prueba unitaria en el ensamblado que están probando en un espacio de nombre ''UnitTest'' debajo del ''predeterminado'' para ese ensamblado: cada archivo de prueba está envuelto en un:
#if DEBUG
...test code...
#endif
bloquear, y todo eso significa que a) no se está distribuyendo en un lanzamiento yb) Puedo usar declaraciones de nivel internal
/ Friend
sin saltos de aro.
La otra cosa que esto ofrece, más pertinente a esta pregunta, es el uso de clases partial
, que se pueden usar para crear un proxy para probar métodos privados, por ejemplo para probar algo así como un método privado que devuelve un valor entero:
public partial class TheClassBeingTested
{
private int TheMethodToBeTested() { return -1; }
}
en las clases principales del ensamblado y la clase de prueba:
#if DEBUG
using NUnit.Framework;
public partial class TheClassBeingTested
{
internal int NUnit_TheMethodToBeTested()
{
return TheMethodToBeTested();
}
}
[TestFixture]
public class ClassTests
{
[Test]
public void TestMethod()
{
var tc = new TheClassBeingTested();
Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
}
}
#endif
Obviamente, debe asegurarse de no utilizar este método mientras desarrolla, aunque una versión de lanzamiento pronto indicará una inadvertida llamada si lo hace.
Estoy a favor de tener la capacidad de probar métodos privados. Cuando xUnit comenzó, fue diseñado para probar la funcionalidad después de que se escribió el código. Probar la interfaz es suficiente para este propósito.
Las pruebas unitarias han evolucionado para convertirse en pruebas impulsadas. Tener la capacidad de probar todos los métodos es útil para esa aplicación.
Generalmente, las pruebas unitarias abordan la interfaz pública de una clase, en la teoría de que la implementación es inmaterial, siempre y cuando los resultados sean correctos desde el punto de vista del cliente.
Por lo tanto, NUnit no proporciona ningún mecanismo para probar miembros no públicos.
Haría visible el paquete de métodos privados. De esta manera, lo mantendrá razonablemente privado mientras aún puede probar esos métodos. No estoy de acuerdo con la gente que dice que las interfaces públicas son las únicas que deben probarse. A menudo hay un código realmente crítico en los métodos privados que no se puede probar de manera adecuada solo a través de las interfaces externas.
Entonces, realmente se reduce a si le preocupa más el código correcto o la ocultación de información. Yo diría que la visibilidad del paquete es un buen compromiso ya que para acceder a esos métodos alguien debería colocar su clase en su paquete. Eso realmente debería hacer que piensen dos veces acerca de si eso es realmente algo inteligente que hacer.
Soy un tipo de Java por cierto, por lo que la visibilidad del paquete podría llamarse algo completamente diferente en C #. Basta decir que es cuando dos clases tienen que estar en el mismo espacio de nombres para acceder a esos métodos.
No prueba funciones privadas. Hay formas de usar la reflexión para acceder a métodos y propiedades privados. Pero eso no es realmente fácil y desaconsejo firmemente esta práctica.
Simplemente no debe probar nada que no sea público.
Si tiene algunos métodos y propiedades internos, debería considerar cambiarlos a públicos o enviar sus pruebas con la aplicación (algo que realmente no veo como un problema).
Si su cliente puede ejecutar Test-Suite y ver que el código que entregó está realmente "funcionando", no veo esto como un problema (siempre y cuando no revele su IP a través de esto). Las cosas que incluyo en cada lanzamiento son informes de prueba e informes de cobertura de código.
Puede proteger internamente sus métodos y luego usar assembly: InternalVisibleTo("NAMESPACE")
en su espacio de nombres de prueba.
Por lo tanto, ¡NO! No puede acceder a métodos privados, pero esto es una solución alternativa.
Si bien estoy de acuerdo con que el foco de las pruebas unitarias debe ser la interfaz pública, obtendrá una impresión mucho más granular de su código si también prueba métodos privados. El marco de prueba de MS permite esto a través del uso de PrivateObject y PrivateType, NUnit no lo hace. Lo que hago en cambio es:
private MethodInfo GetMethod(string methodName)
{
if (string.IsNullOrWhiteSpace(methodName))
Assert.Fail("methodName cannot be null or whitespace");
var method = this.objectUnderTest.GetType()
.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
Assert.Fail(string.Format("{0} method not found", methodName));
return method;
}
De esta forma, significa que no debe comprometer la encapsulación a favor de la capacidad de prueba. Tenga en cuenta que deberá modificar sus BindingFlags si desea probar métodos estáticos privados. El ejemplo anterior es solo por ejemplo métodos.
Un patrón común para escribir pruebas unitarias es solo probar métodos públicos.
Si encuentra que tiene muchos métodos privados que desea probar, normalmente esto es una señal de que debe refactorizar su código.
Sería un error hacer públicos estos métodos en la clase en la que viven actualmente. Eso rompería el contrato que quieres que tenga esa clase.
Puede ser correcto moverlos a una clase auxiliar y hacerlos públicos allí. Esta clase puede no estar expuesta por tu API.
De esta forma, el código de prueba nunca se mezcla con tu código público.
Un problema similar es probar clases privadas, es decir. clases que no exportas de tu ensamblado. En este caso, puede hacer explícitamente que su ensamblado de código de prueba sea un amigo del ensamblaje del código de producción usando el atributo InternalsVisibleTo.