Visual Studio permite pruebas unitarias de métodos privados a través de una clase de acceso generada automáticamente. He escrito una prueba de un método privado que se compila con éxito, pero falla en tiempo de ejecución. Una versión bastante mínima del código y la prueba es:
//in project MyProj
class TypeA
{
private List<TypeB> myList = new List<TypeB>();
private class TypeB
{
public TypeB()
{
}
}
public TypeA()
{
}
private void MyFunc()
{
//processing of myList that changes state of instance
}
}
//in project TestMyProj
public void MyFuncTest()
{
TypeA_Accessor target = new TypeA_Accessor();
//following line is the one that throws exception
target.myList.Add(new TypeA_Accessor.TypeB());
target.MyFunc();
//check changed state of target
}
El error de tiempo de ejecución es:
Object of type System.Collections.Generic.List`1[MyProj.TypeA.TypeA_Accessor+TypeB]' cannot be converted to type 'System.Collections.Generic.List`1[MyProj.TypeA.TypeA+TypeB]'.
De acuerdo con intellisense, y por lo tanto supongo que el compilador, el destino es de tipo TypeA_Accessor. Pero en tiempo de ejecución es de tipo TypeA, y por lo tanto, la lista de agregar falla.
¿Hay alguna forma de detener este error? O, quizás más probablemente, qué otro consejo tienen otras personas (predigo que tal vez "no pruebe métodos privados" y "no haga que las pruebas unitarias manipulen el estado de los objetos").
c#
unit-testing
junichiro
fuente
fuente
Respuestas:
Sí, no pruebe métodos privados ... La idea de una prueba unitaria es probar la unidad mediante su 'API' pública.
Si descubre que necesita probar una gran cantidad de comportamiento privado, lo más probable es que tenga una nueva 'clase' escondida dentro de la clase que está tratando de probar, extráigala y pruébela por su interfaz pública.
Un consejo / herramienta de pensamiento ... Existe la idea de que ningún método debería ser privado. Es decir, todos los métodos deberían vivir en una interfaz pública de un objeto ... si siente que necesita hacerlo privado, lo más probable es que viva en otro objeto.
Este consejo no funciona en la práctica, pero en su mayoría es un buen consejo, y a menudo empujará a las personas a descomponer sus objetos en objetos más pequeños.
fuente
Puede usar la clase PrivateObject
fuente
"No hay nada llamado estándar o mejor práctica, probablemente son solo opiniones populares".
Lo mismo es válido para esta discusión también.
Todo depende de lo que creas que es una unidad, si crees que UNIT es una clase, solo accederás al método público. Si crees que UNIT tiene líneas de código que tocan métodos privados, no te sentirás culpable.
Si desea invocar métodos privados, puede usar la clase "PrivateObject" y llamar al método invoke. Puede ver este video de YouTube en profundidad ( http://www.youtube.com/watch?v=Vq6Gcs9LrPQ ) que muestra cómo usar "PrivateObject" y también discute si las pruebas de métodos privados son lógicas o no.
fuente
Otro pensamiento aquí es extender las pruebas a clases / métodos "internos", dando más sentido de caja blanca a estas pruebas. Puede usar InternalsVisibleToAttribute en el ensamblaje para exponerlos a módulos de prueba de unidades separadas.
En combinación con la clase sellada, puede acercarse a tal encapsulación que el método de prueba sea visible solo desde el ensamblaje de la unidad de prueba de sus métodos. Considere que el método protegido en clase sellada es de facto privado.
Y prueba unitaria:
fuente
Una forma de probar métodos privados es a través de la reflexión. Esto también se aplica a NUnit y XUnit:
fuente
call methods
estática y no estática ?Ermh ... Llegué aquí con exactamente el mismo problema: pruebe un método privado simple pero fundamental . Después de leer este hilo, parece ser como "Quiero perforar este simple agujero en esta simple pieza de metal, y quiero asegurarme de que la calidad cumpla con las especificaciones", y luego viene "Bien, esto no es tan fácil. En primer lugar, no existe una herramienta adecuada para hacerlo, pero podría construir un observatorio de ondas gravitacionales en su jardín. Lea mi artículo en http://foobar.brigther-than-einstein.org/ Primero, por supuesto, usted tiene que asistir a algunos cursos avanzados de física cuántica, luego necesita toneladas de nitrógeno ultrafrío, y luego, por supuesto, mi libro disponible en Amazon "...
En otras palabras...
No, lo primero es lo primero.
Todos y cada método, se pueden privada, interna, protegido, público tiene que ser comprobable. Tiene que haber una manera de implementar tales pruebas sin tanta dificultad como se presentó aquí.
¿Por qué? Exactamente por las menciones arquitectónicas hechas hasta ahora por algunos colaboradores. Quizás una simple reiteración de los principios del software pueda aclarar algunos malentendidos.
En este caso, los sospechosos habituales son: OCP, SRP y, como siempre, KIS.
Pero espera un minuto. La idea de hacer que todo esté a disposición del público es más bien menos político y una especie de actitud. Pero. Cuando se trata de código, incluso en la comunidad de código abierto, esto no es un dogma. En cambio, "ocultar" algo es una buena práctica para que sea más fácil familiarizarse con una determinada API. Ocultaría, por ejemplo, los cálculos básicos de su nuevo componente de termómetro digital, no para ocultar las matemáticas detrás de la curva real medida a lectores curiosos de códigos, sino para evitar que su código se vuelva dependiente de algunos, quizás usuarios repentinamente importantes que no pudieron resistir el uso de su código privado, interno y protegido para implementar sus propias ideas.
De que estoy hablando
Es fácil proclamar la Era de Acuario o lo que se llama hoy en día, pero si mi sensor pasa de 1.0 a 2.0, la implementación de Traducir ... podría cambiar de una ecuación lineal simple que es fácilmente comprensible y "re usable "para todos, para un cálculo bastante sofisticado que usa análisis o lo que sea, y entonces rompería el código de otros. ¿Por qué? Porque no entendían los mismos principios de la codificación de software, ni siquiera KIS.
Para abreviar este cuento de hadas: necesitamos una forma simple de probar métodos privados, sin preámbulos.
Primero: ¡Feliz año nuevo a todos!
Segundo: ensaya tus lecciones de arquitecto.
Tercero: El modificador "público" es religión, no una solución.
fuente
Otra opción que no se ha mencionado es simplemente crear la clase de prueba unitaria como elemento secundario del objeto que está probando. NUnit Ejemplo:
Esto permitiría probar fácilmente métodos privados y protegidos (pero no heredados), y le permitiría mantener todas sus pruebas separadas del código real para que no esté implementando ensambles de prueba en producción. Cambiar sus métodos privados a métodos protegidos sería aceptable en muchos objetos heredados, y es un cambio bastante simple de hacer.
SIN EMBARGO...
Si bien este es un enfoque interesante para resolver el problema de cómo probar métodos ocultos, no estoy seguro de que recomendaría que esta sea la solución correcta al problema en todos los casos. Parece un poco extraño probar internamente un objeto, y sospecho que puede haber algunos escenarios en los que este enfoque explote. (Los objetos inmutables, por ejemplo, pueden hacer que algunas pruebas sean realmente difíciles).
Si bien menciono este enfoque, sugeriría que se trata más de una lluvia de ideas que de una solución legítima. Tómelo con un grano de sal.
EDITAR: Encuentro realmente divertido que la gente esté rechazando esta respuesta, ya que explícitamente lo describo como una mala idea. ¿Eso significa que la gente está de acuerdo conmigo? Estoy muy confundido.....
fuente
Del libro Trabajando efectivamente con código heredado :
La forma de solucionarlo, según el autor, es creando una nueva clase y agregando el método como
public
.El autor explica además:
Entonces, dentro de estos límites, su única opción real es hacer el método
public
, ya sea en la clase actual o en una nueva.fuente
TL; DR: Extraiga el método privado a otra clase, pruebe en esa clase; Lea más sobre el principio SRP (Principio de responsabilidad única)
Parece que necesita extraer el
private
método a otra clase; en esto debería serpublic
. En lugar de intentar probar elprivate
método, debe probar elpublic
método de esta otra clase.Tenemos el siguiente escenario:
Necesitamos probar la lógica de
_someLogic
; pero parece queClass A
tiene más papel del que necesita (viola el principio SRP); simplemente refactorizar en dos clasesDe esta manera
someLogic
podría probarse en A2; en A1 solo cree un falso A2 y luego inyecte al constructor para probar que A2 se llama a la función nombradasomeLogic
.fuente
En VS 2005/2008, puede usar un descriptor de acceso privado para probar un miembro privado, pero de esta forma desapareció en una versión posterior de VS
fuente