¿Cómo se prueba una función privada en angular 2?
class FooBar {
private _status: number;
constructor( private foo : Bar ) {
this.initFooBar();
}
private initFooBar(){
this.foo.bar( "data" );
this._status = this.fooo.foo();
}
public get status(){
return this._status;
}
}
La solución que encontré
Coloque el código de prueba dentro del cierre o Agregue código dentro del cierre que almacene referencias a las variables locales en objetos existentes en el ámbito externo.
Luego, elimine el código de prueba con una herramienta. http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/
¿Me ha sugerido una mejor manera de resolver este problema si ya lo hizo?
PD
La mayor parte de la respuesta para un tipo similar de pregunta como esta no da una solución al problema, es por eso que hago esta pregunta
La mayoría de los desarrolladores dicen que no pruebes las funciones privadas, pero no digo que sean incorrectas o correctas, pero es necesario que mi caso sea privado.
fuente
Respuestas:
Estoy con usted, a pesar de que es un buen objetivo "probar solo la unidad de la API pública", hay momentos en que no parece tan simple y siente que está eligiendo entre comprometer la API o las pruebas unitarias. Ya lo sabes, ya que eso es exactamente lo que estás pidiendo que hagas, así que no voy a entrar en eso. :)
En TypeScript he descubierto algunas formas en que puede acceder a miembros privados por el simple hecho de realizar pruebas unitarias. Considera esta clase:
A pesar de que el acceso TS restringe a miembros de la clase usando
private
,protected
,public
, el JS compilado no tiene usuarios privados, ya que esto no es una cosa en JS. Se usa exclusivamente para el compilador de TS. Por lo tanto:Puede hacer valer
any
y evitar que el compilador le advierta sobre restricciones de acceso:El problema con este enfoque es que el compilador simplemente no tiene idea de lo que está haciendo correctamente
any
, por lo que no obtiene los errores de tipo deseados:Obviamente, esto hará que la refactorización sea más difícil.
Puede usar el acceso a la matriz (
[]
) para acceder a los miembros privados:Si bien parece funky, TSC realmente validará los tipos como si accediera a ellos directamente:
Para ser sincero, no sé por qué funciona esto.Aparentemente, esta es una "escotilla de escape" intencional para darle acceso a miembros privados sin perder la seguridad del tipo. Esto es exactamente lo que creo que quieres para tu prueba de unidad.Aquí hay un ejemplo de trabajo en TypeScript Playground .
Editar para TypeScript 2.6
Otra opción que a algunos les gusta es usar
// @ts-ignore
( agregado en TS 2.6 ) que simplemente suprime todos los errores en la siguiente línea:El problema con esto es, bueno, suprime todos los errores en la siguiente línea:
Personalmente considero
@ts-ignore
un olor a código, y como dicen los documentos:fuente
as any
: pierde toda la verificación de tipos.Puedes llamar a métodos privados . Si encontró el siguiente error:
solo usa
// @ts-ignore
:fuente
as any
que pierde cualquier verificación de tipo, en realidad pierde cualquier verificación de tipo en toda la línea.Como la mayoría de los desarrolladores no recomiendan probar la función privada , ¿por qué no probarla?
P.ej.
YourClass.ts
TestYourClass.spec.ts
Gracias a @Aaron, @Thierry Templier.
fuente
No escriba pruebas para métodos privados. Esto derrota el punto de las pruebas unitarias.
Ejemplo
La prueba para este método no debería necesitar cambiar si luego la implementación cambia, pero la
behaviour
API pública sigue siendo la misma.No haga públicos los métodos y propiedades solo para probarlos. Esto generalmente significa que:
fuente
El punto de "no probar métodos privados" realmente es probar la clase como alguien que la usa .
Si tiene una API pública con 5 métodos, cualquier consumidor de su clase puede usarlos y, por lo tanto, debe probarlos. Un consumidor no debe acceder a los métodos / propiedades privados de su clase, lo que significa que puede cambiar los miembros privados cuando la funcionalidad pública expuesta permanece igual.
Si confía en la funcionalidad interna extensible, use en
protected
lugar deprivate
.Tenga en cuenta que
protected
todavía es una API pública (!) , Solo que se usa de manera diferente.Prueba unitaria de propiedades protegidas de la misma manera que un consumidor las usaría, a través de subclases:
fuente
Esto funcionó para mí:
En vez de:
Esta:
fuente
Perdón por el necro en esta publicación, pero me siento obligado a opinar sobre un par de cosas que no parecen haber sido tocadas.
Primero, lo más importante: cuando nos encontramos necesitando acceso a miembros privados en una clase durante las pruebas de la unidad, generalmente es una gran y gruesa bandera roja que nos hemos burlado de nuestro enfoque estratégico o táctico y hemos violado inadvertidamente el principio de responsabilidad individual al presionar comportamiento donde no pertenece. Sentir la necesidad de acceder a métodos que realmente no son más que una subrutina aislada de un procedimiento de construcción es uno de los casos más comunes de esto; sin embargo, es como si tu jefe esperara que aparecieras listo para trabajar y también tuviera una necesidad perversa de saber qué rutina matutina seguiste para llegar a ese estado ...
La otra instancia más común de este suceso es cuando te encuentras tratando de probar la proverbial "clase de dios". Es un tipo especial de problema en sí mismo, pero sufre el mismo problema básico con la necesidad de conocer detalles íntimos de un procedimiento, pero eso está saliendo del tema.
En este ejemplo específico, hemos asignado efectivamente la responsabilidad de inicializar completamente el objeto Bar al constructor de la clase FooBar. En la programación orientada a objetos, uno de los principales núcleos es que el constructor es "sagrado" y debe protegerse contra datos no válidos que invalidarían su propio estado interno y lo dejarían preparado para fallar en otro lugar aguas abajo (en lo que podría ser muy profundo). tubería.)
No hemos podido hacer eso aquí al permitir que el objeto FooBar acepte una barra que no está lista en el momento en que se construye el FooBar, y lo hemos compensado mediante una especie de "pirateo" del objeto FooBar para que tome las cosas en cuenta manos.
Este es el resultado de una falla en adherirse a otra unidad de programación orientada a objetos (en el caso de Bar), que es que el estado de un objeto debe estar completamente inicializado y listo para manejar cualquier llamada entrante a sus miembros públicos inmediatamente después de la creación. Ahora, esto no significa inmediatamente después de que se llame al constructor en todas las instancias. Cuando tiene un objeto que tiene muchos escenarios de construcción complejos, es mejor exponer a los setters a sus miembros opcionales a un objeto que se implemente de acuerdo con un patrón de diseño de creación (Factory, Builder, etc.) en cualquiera de los últimos casos
En su ejemplo, la propiedad "status" de la barra no parece estar en un estado válido en el que un FooBar pueda aceptarla, por lo que FooBar hace algo para corregir ese problema.
El segundo problema que veo es que parece que está intentando probar su código en lugar de practicar el desarrollo basado en pruebas. Esta es definitivamente mi propia opinión en este momento; pero, este tipo de prueba es realmente un antipatrón. Lo que termina haciendo es caer en la trampa de darse cuenta de que tiene problemas centrales de diseño que impiden que su código sea verificable después del hecho, en lugar de escribir las pruebas que necesita y posteriormente programarlas para las pruebas. De cualquier forma que se encuentre con el problema, aún debería terminar con la misma cantidad de pruebas y líneas de código si realmente hubiera logrado una implementación SÓLIDA. Entonces, ¿por qué tratar de aplicar ingeniería inversa en código comprobable cuando puede abordar el asunto al comienzo de sus esfuerzos de desarrollo?
Si lo hubiera hecho, entonces se habría dado cuenta mucho antes de que tendría que escribir un código bastante asqueroso para probar su diseño y habría tenido la oportunidad desde el principio de realinear su enfoque cambiando el comportamiento a implementaciones que son fácilmente comprobables
fuente
Estoy de acuerdo con @toskv: no recomendaría hacer eso :-)
Pero si realmente quiere probar su método privado, puede tener en cuenta que el código correspondiente para TypeScript corresponde a un método del prototipo de la función de constructor. Esto significa que puede usarse en tiempo de ejecución (mientras que probablemente tendrá algunos errores de compilación).
Por ejemplo:
será trasladado a:
Vea este plunkr: https://plnkr.co/edit/calJCF?p=preview .
fuente
Como muchos ya han dicho, por mucho que quieras probar los métodos privados, no debes hackear tu código o transpiler para que funcione para ti. TypeScript moderno negará la mayoría de los hacks que la gente ha proporcionado hasta ahora.
Solución
TLDR ; si un método debe ser probado, entonces debe desacoplar el código en una clase en la que pueda exponer el método para que sea público para ser probado.
La razón por la que tiene el método privado es porque la funcionalidad no necesariamente debe estar expuesta por esa clase y, por lo tanto, si la funcionalidad no pertenece allí, debe desacoplarse en su propia clase.
Ejemplo
Me encontré con este artículo que hace un gran trabajo al explicar cómo debes abordar probar métodos privados. Incluso cubre algunos de los métodos aquí y cómo son malas implementaciones.
https://patrickdesjardins.com/blog/how-to-unit-test-private-method-in-typescript-part-2
Nota : Este código se elimina del blog vinculado anteriormente (estoy duplicando en caso de que cambie el contenido detrás del enlace)
antes de Despuésfuente
llamar al método privado usando corchetes
Archivo Ts
archivo spect.ts
fuente
La respuesta de Aaron es la mejor y está funcionando para mí :) Lo votaría pero lamentablemente no puedo (falta reputación).
Debo decir que probar métodos privados es la única forma de usarlos y tener un código limpio en el otro lado.
Por ejemplo:
Tiene mucho sentido no probar todos estos métodos a la vez porque tendríamos que burlarnos de esos métodos privados, que no podemos burlarnos porque no podemos acceder a ellos. Esto significa que necesitamos mucha configuración para que una prueba unitaria pruebe esto en su conjunto.
Esto dijo que la mejor manera de probar el método anterior con todas las dependencias es una prueba de extremo a extremo, porque aquí se necesita una prueba de integración, pero la prueba E2E no lo ayudará si está practicando TDD (Test Driven Development), pero prueba Cualquier método lo hará.
fuente
Esta ruta que tomo es una en la que creo funciones fuera de la clase y asigno la función a mi método privado.
Ahora no sé qué tipo de reglas de OOP estoy rompiendo, pero para responder a la pregunta, así es como pruebo los métodos privados. Doy la bienvenida a cualquiera para que asesore sobre Pros y Contras de esto.
fuente