unit testing - unitario - ¿Debo probar métodos privados o solo públicos?
test unitarios javascript (27)
¿Cuál es el propósito de la prueba?
La mayoría de las respuestas hasta ahora dicen que los métodos privados son detalles de implementación que no importan (o al menos no deberían), siempre y cuando la interfaz pública esté bien probada y funcione. Eso es absolutamente correcto si su único propósito de prueba es garantizar que la interfaz pública funcione .
Personalmente, mi uso principal para las pruebas de código es asegurar que futuros cambios en el código no causen problemas y para ayudar en mis esfuerzos de depuración si lo hacen. Encuentro que probar los métodos privados tan a fondo como la interfaz pública (¡si no más!) Promueve ese propósito.
Considere: Tiene el método público A, que llama al método privado B. Tanto A como B utilizan el método C. C cambia (tal vez usted, quizás por un proveedor), lo que hace que A comience a fallar sus pruebas. ¿No sería útil tener pruebas para B también, aunque sea privada, para que sepa si el problema está en el uso de C por parte de A, B, o ambos?
La prueba de métodos privados también agrega valor en los casos en que la cobertura de prueba de la interfaz pública está incompleta. Si bien esta es una situación que generalmente queremos evitar, la prueba de la unidad de eficiencia depende tanto de las pruebas que detectan errores como de los costos asociados de desarrollo y mantenimiento de esas pruebas. En algunos casos, los beneficios de una cobertura de prueba del 100% pueden considerarse insuficientes para justificar los costos de esas pruebas, lo que produce brechas en la cobertura de prueba de la interfaz pública. En tales casos, una prueba bien dirigida de un método privado puede ser una adición muy efectiva al código base.
He leído este post sobre cómo probar métodos privados. Normalmente no los pruebo, porque siempre pensé que es más rápido probar solo los métodos públicos que se llamarán desde fuera del objeto. ¿Pruebas métodos privados? ¿Debo siempre probarlos?
Como se mencionó anteriormente, "Si no prueba sus métodos privados, ¿cómo sabe que no se romperán?"
Este es un problema importante. Uno de los puntos importantes de las pruebas unitarias es saber dónde, cuándo y cómo algo se rompió lo antes posible. Disminuyendo así una cantidad significativa de desarrollo y esfuerzo de control de calidad. Si todo lo que se prueba es el público, entonces no tiene una cobertura y una descripción honestas de los aspectos internos de la clase.
He encontrado que una de las mejores maneras de hacer esto es simplemente agregar la referencia de prueba al proyecto y colocar las pruebas en una clase paralela a los métodos privados. Coloque la lógica de compilación adecuada para que las pruebas no se integren en el proyecto final.
Entonces tiene todos los beneficios de tener estos métodos probados y puede encontrar problemas en segundos o minutos u horas.
Así que en resumen, sí, prueba tu unidad de tus métodos privados.
Creo que es mejor probar la interfaz pública de un objeto. Desde el punto de vista del mundo exterior, solo importa el comportamiento de la interfaz pública y es a esto a lo que deben dirigirse las pruebas de unidad.
Una vez que haya escrito algunas pruebas de unidad sólidas para un objeto, no querrá tener que retroceder y cambiar esas pruebas solo porque la implementación detrás de la interfaz cambió. En esta situación, ha arruinado la consistencia de sus pruebas de unidad.
Entiendo el punto de vista donde los métodos privados se consideran como detalles de implementación y luego no tienen que ser probados. Y seguiría esta regla si tuviéramos que desarrollarnos fuera del objeto solamente. Pero nosotros, ¿somos algún tipo de desarrolladores restringidos que estamos desarrollando solo fuera de los objetos, llamando solo a sus métodos públicos? ¿O estamos desarrollando también ese objeto?Como no estamos obligados a programar objetos externos, probablemente tendremos que convertir esos métodos privados en nuevos públicos que estamos desarrollando. ¿No sería genial saber que el método privado se resiste contra todo pronóstico?
Sé que algunas personas podrían responder que si estamos desarrollando otro método público en ese objeto, entonces este debería probarse y ya está (el método privado podría continuar viviendo sin prueba). Pero esto también es válido para cualquier método público de un objeto: al desarrollar una aplicación web, todos los métodos públicos de un objeto se llaman desde los métodos de los controladores y, por lo tanto, podrían considerarse como detalles de implementación para los controladores.
Entonces, ¿por qué estamos probando objetos de unidad? Debido a que es realmente difícil, por no decir imposible, estar seguro de que estamos probando los métodos de los controladores con la entrada apropiada que activará todas las ramas del código subyacente. En otras palabras, cuanto más alto estamos en la pila, más difícil es probar todo el comportamiento. Y lo mismo ocurre con los métodos privados.
Para mí, la frontera entre los métodos privados y públicos es un criterio psicológico cuando se trata de pruebas. Los criterios que más me importan son:
- ¿Se llama el método más de una vez desde diferentes lugares?
- ¿Es el método lo suficientemente sofisticado como para requerir pruebas?
Es obviamente dependiente del lenguaje. En el pasado, con c ++, he declarado que la clase de prueba es una clase de amigos. Desafortunadamente, esto requiere que su código de producción sepa acerca de la clase de prueba.
He estado discutiendo sobre este tema por un tiempo, especialmente con probar mi mano en TDD.
Me he encontrado con dos publicaciones que creo que abordan este problema lo suficientemente a fondo en el caso de TDD.
En resumen:
Cuando se usan técnicas de desarrollo (diseño) impulsadas por pruebas, los métodos privados deben surgir solo durante el proceso de re-factorización de un código que ya está funcionando y probado.
Debido a la naturaleza misma del proceso, cualquier parte de la funcionalidad de implementación simple extraída de una función probada a fondo será autocomprobada (es decir, cobertura de prueba indirecta).
A mí me parece suficientemente claro que, al principio, la parte de la codificación de la mayoría de los métodos serán funciones de nivel superior porque están encapsulando / describiendo el diseño.
Por lo tanto, estos métodos serán públicos y probarlos será bastante fácil.
Los métodos privados vendrán más tarde, una vez que todo esté funcionando bien y estamos rediseñando para facilitar la lectura y la limpieza .
Me siento obligado a probar funciones privadas, ya que sigo cada vez más una de nuestras últimas recomendaciones de control de calidad en nuestro proyecto:
No más de 10 en complejidad ciclomática por función.
Ahora, el efecto secundario de la aplicación de esta política es que muchas de mis funciones públicas de gran tamaño se dividen en muchas funciones privadas mejor enfocadas y con mejor nombre.
La función pública sigue ahí (por supuesto), pero se reduce esencialmente a todas esas sub-funciones privadas llamadas
Eso es realmente genial, porque ahora es mucho más fácil leer el callstack (en lugar de un error dentro de una función grande, tengo un error en una sub-sub-función con el nombre de las funciones anteriores en el callstack para ayudarme a entender ''cómo llegué allí'')
Sin embargo, ahora parece más fácil realizar una prueba unitaria directamente de esas funciones privadas , y dejar la prueba de la función pública general a algún tipo de prueba de "integración" donde se debe abordar un escenario.
Sólo mis 2 centavos.
No hago pruebas unitarias de métodos privados. Un método privado es un detalle de implementación que se debe ocultar a los usuarios de la clase. La prueba de métodos privados rompe la encapsulación.
Si encuentro que el método privado es enorme o complejo o lo suficientemente importante como para requerir sus propias pruebas, simplemente lo pongo en otra clase y lo hago público allí ( Método Objeto ) Entonces puedo probar fácilmente el método previamente privado pero ahora público que ahora vive en su propia clase.
No me gusta probar la funcionalidad privada por un par de razones. Son los siguientes (estos son los puntos principales para las personas de TLDR):
- Normalmente, cuando estás tentado a probar el método privado de una clase, es un olor a diseño.
- Puede probarlos a través de la interfaz pública (que es como desea probarlos, porque así es como el cliente los llamará / usará). Puede obtener una falsa sensación de seguridad al ver la luz verde en todas las pruebas de aprobación para sus métodos privados. Es mucho mejor / más seguro probar casos perimetrales en sus funciones privadas a través de su interfaz pública.
- Corre el riesgo de duplicación de pruebas severas (pruebas que se ven / sienten muy similares) al probar métodos privados. Esto tiene consecuencias importantes cuando los requisitos cambian, ya que se romperán más pruebas de las necesarias. También puede ponerlo en una posición en la que es difícil refactorizar debido a su conjunto de pruebas ... ¡lo cual es la máxima ironía, ya que el conjunto de pruebas está ahí para ayudarlo a rediseñar y refactorear de manera segura!
Explicaré cada uno de estos con un ejemplo concreto. Resulta que 2) y 3) están un tanto intrincadamente conectados, por lo que su ejemplo es similar, aunque los considero razones separadas por las que no deberías probar métodos privados.
Hay una vez que considero que los métodos privados de prueba son apropiados, pero luego lo explicaré con más detalle.
También explico por qué TDD no es una excusa válida para probar métodos privados al final.
Refactorizando tu salida de un mal diseño.
Uno de los paternos (anti) más comunes que veo es lo que Michael Feathers llama una clase de "Iceberg" (si no sabe quién es Michael Feathers, vaya a comprar / leer su libro "Trabajando de manera efectiva con el código heredado". Es una persona que vale la pena conocer si usted es un ingeniero / desarrollador de software profesional). Hay otros (anti) patrones que hacen que este problema surja, pero este es, con mucho, el más común que he encontrado. Las clases "iceberg" tienen un método público, y el resto son privadas (por lo que es tentador probar los métodos privados). Se denomina clase "Iceberg" porque generalmente existe un método público único que se asoma, pero el resto de la funcionalidad se oculta bajo el agua en forma de métodos privados. Podría verse algo como esto:
Por ejemplo, es posible que desee probar GetNextToken()
llamándolo en una cadena sucesivamente y viendo que devuelve el resultado esperado. Una función como esta justifica una prueba: ese comportamiento no es trivial, especialmente si las reglas de tokenización son complejas. Supongamos que no es tan complejo, y solo queremos atar en fichas delimitadas por el espacio. Así que escribes una prueba, tal vez se vea algo como esto (un poco de lenguaje pseudocodificado, ojala la idea sea clara):
TEST_THAT(RuleEvaluator, canParseSpaceDelimtedTokens)
{
input_string = "1 2 test bar"
re = RuleEvaluator(input_string);
ASSERT re.GetNextToken() IS "1";
ASSERT re.GetNextToken() IS "2";
ASSERT re.GetNextToken() IS "test";
ASSERT re.GetNextToken() IS "bar";
ASSERT re.HasMoreTokens() IS FALSE;
}
Bueno, en realidad se ve muy bien. Queremos asegurarnos de mantener este comportamiento mientras hacemos cambios. ¡Pero GetNextToken()
es una función privada ! Por lo tanto, no podemos probarlo de esta manera, ya que ni siquiera se compila (asumiendo que estamos usando algún lenguaje que realmente aplique público / privado, a diferencia de algunos lenguajes de script como Python). Pero, ¿qué hay de cambiar la clase RuleEvaluator
para seguir el Principio de Responsabilidad Única (Principio de Responsabilidad Única)? Por ejemplo, parece que tenemos un analizador, un tokenizador y un evaluador atascados en una clase. ¿No sería mejor separar esas responsabilidades? Además de eso, si creas una clase Tokenizer
, entonces sus métodos públicos serían HasMoreTokens()
y GetNextTokens()
. La clase RuleEvaluator
podría tener un objeto Tokenizer
como miembro. Ahora, podemos mantener la misma prueba que la anterior, excepto que estamos probando la clase Tokenizer
lugar de la clase RuleEvaluator
.
Esto es lo que podría parecer en UML:
Tenga en cuenta que este nuevo diseño aumenta la modularidad, por lo que potencialmente podría reutilizar estas clases en otras partes de su sistema (antes de que no pudiera, los métodos privados no son reutilizables por definición). Esta es la principal ventaja de descomponer el RuleEvaluator, junto con una mayor comprensión / localidad.
La prueba se vería extremadamente similar, excepto que en realidad se compilaría esta vez ya que el método GetNextToken()
ahora es público en la clase Tokenizer
:
TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens)
{
input_string = "1 2 test bar"
tokenizer = Tokenizer(input_string);
ASSERT tokenizer.GetNextToken() IS "1";
ASSERT tokenizer.GetNextToken() IS "2";
ASSERT tokenizer.GetNextToken() IS "test";
ASSERT tokenizer.GetNextToken() IS "bar";
ASSERT tokenizer.HasMoreTokens() IS FALSE;
}
Probar componentes privados a través de una interfaz pública y evitar la duplicación de pruebas
Incluso si piensa que no puede dividir su problema en menos componentes modulares (lo que puede hacer el 95% del tiempo si intenta hacerlo), simplemente puede probar las funciones privadas a través de una interfaz pública. Muchas veces los miembros privados no valen la pena probarlos porque serán probados a través de la interfaz pública. Muchas veces, lo que veo son pruebas que parecen muy similares, pero que prueban dos funciones / métodos diferentes. Lo que termina sucediendo es que cuando los requisitos cambian (y siempre lo hacen), ahora tiene 2 pruebas rotas en lugar de 1. Y si realmente probó todos sus métodos privados, podría tener más de 10 pruebas rotas en lugar de 1. En resumen , probar funciones privadas (al usar FRIEND_TEST
o hacerlas públicas o usar reflexiones) que de otro modo podrían probarse a través de una interfaz pública puede causar la duplicación de pruebas . Realmente no quieres esto, porque nada duele más que tu conjunto de pruebas que te ralentiza. ¡Se supone que reduce el tiempo de desarrollo y los costos de mantenimiento! Si prueba métodos privados que de otro modo se prueban a través de una interfaz pública, el conjunto de pruebas puede hacer lo contrario e incrementar activamente los costos de mantenimiento e incrementar el tiempo de desarrollo. Cuando haces pública una función privada, o si usas algo como FRIEND_TEST
y / o reflexión, por lo general terminarás arrepintiéndote a largo plazo.
Considere la siguiente posible implementación de la clase Tokenizer
:
Digamos que SplitUpByDelimiter()
es responsable de devolver una matriz de manera que cada elemento de la matriz sea un token. Además, digamos que GetNextToken()
es simplemente un iterador de este vector. Por lo que su prueba pública podría tener este aspecto:
TEST_THAT(Tokenizer, canParseSpaceDelimtedTokens)
{
input_string = "1 2 test bar"
tokenizer = Tokenizer(input_string);
ASSERT tokenizer.GetNextToken() IS "1";
ASSERT tokenizer.GetNextToken() IS "2";
ASSERT tokenizer.GetNextToken() IS "test";
ASSERT tokenizer.GetNextToken() IS "bar";
ASSERT tokenizer.HasMoreTokens() IS false;
}
Supongamos que tenemos lo que Michael Feather llama una herramienta de búsqueda . Esta es una herramienta que te permite tocar las partes privadas de otras personas. Un ejemplo es FRIEND_TEST
de googletest, o reflexión si el lenguaje lo admite.
TEST_THAT(TokenizerTest, canGenerateSpaceDelimtedTokens)
{
input_string = "1 2 test bar"
tokenizer = Tokenizer(input_string);
result_array = tokenizer.SplitUpByDelimiter(" ");
ASSERT result.size() IS 4;
ASSERT result[0] IS "1";
ASSERT result[1] IS "2";
ASSERT result[2] IS "test";
ASSERT result[3] IS "bar";
}
Bueno, ahora digamos que los requisitos cambian, y la tokenización se vuelve mucho más compleja. Decide que un simple delimitador de cadena no será suficiente y necesita una clase Delimiter
para manejar el trabajo. Naturalmente, usted esperará que se rompa una prueba, pero ese dolor aumenta cuando prueba las funciones privadas.
¿Cuándo pueden ser apropiados los métodos privados de prueba?
No hay "una talla para todos" en el software. A veces está bien (y en realidad es ideal) "romper las reglas". Recomiendo firmemente no probar la funcionalidad privada cuando puedas. Hay dos situaciones principales cuando creo que está bien:
He trabajado mucho con sistemas heredados (por lo que soy un gran fan de Michael Feathers), y puedo decir con seguridad que a veces es más seguro probar la funcionalidad privada. Puede ser especialmente útil para obtener "pruebas de caracterización" en la línea de base.
Tienes prisa y tienes que hacer lo más rápido posible aquí y ahora. A largo plazo, no desea probar métodos privados. Pero diré que, por lo general, lleva algún tiempo refactorizar los problemas de diseño. Y a veces hay que enviar en una semana. Está bien: haga lo rápido y sucio, y pruebe los métodos privados utilizando una herramienta de búsqueda si es lo que cree que es la forma más rápida y confiable de hacer el trabajo. Pero entienda que lo que hizo fue subóptimo a largo plazo, y por favor considere regresar a él (o, si se olvidó pero lo ve más tarde, arréglelo).
Probablemente hay otras situaciones en las que está bien. Si crees que está bien, y tienes una buena justificación, hazlo. Nadie te está deteniendo. Solo ten en cuenta los posibles costos.
La excusa de TDD
Además, no me gusta la gente que usa TDD como excusa para probar métodos privados. Practico TDD, y no creo que TDD te obligue a hacer esto. Puede escribir su prueba (para su interfaz pública) primero, y luego escribir código para satisfacer esa interfaz. A veces escribo una prueba para una interfaz pública, y la satisfaceré escribiendo también uno o dos métodos privados más pequeños (pero no pruebo los métodos privados directamente, pero sé que funcionan o que mi prueba pública estaría fallando) ). Si necesito probar casos extremos de ese método privado, escribiré un montón de pruebas que los golpearán a través de mi interfaz pública. Si no puede descubrir cómo llegar a los casos límite, esta es una señal firme de que necesita refactorizar los componentes pequeños, cada uno con sus propios métodos públicos. Es una señal de que las funciones privadas están haciendo demasiado, y fuera del alcance de la clase .
Además, a veces encuentro que escribo una prueba que es demasiado grande para masticarla en este momento, y creo que "eh volveré a esa prueba más adelante cuando tenga más de una API con la que trabajar". Lo comentaré y lo mantendré en el fondo de mi mente. Aquí es donde muchos de los desarrolladores que he conocido comenzarán a escribir pruebas para su funcionalidad privada, utilizando TDD como chivo expiatorio. Ellos dicen "oh, bueno, necesito alguna otra prueba, pero para escribir esa prueba, necesitaré estos métodos privados. Por lo tanto, como no puedo escribir ningún código de producción sin escribir una prueba, necesito escribir una prueba para un método privado ". Pero lo que realmente necesitan hacer es refactorizar en componentes más pequeños y reutilizables en lugar de agregar / probar un montón de métodos privados a su clase actual.
Nota:
Respondí una pregunta similar acerca de probar métodos privados usando GoogleTest hace poco. La mayoría de las veces he modificado esa respuesta para que sea más agnóstico del lenguaje aquí.
PS Aquí está la conferencia relevante sobre las clases de iceberg y las herramientas de investigación de Michael Feathers: https://www.youtube.com/watch?v=4cVZvoFGJTU
No soy un experto en este campo, pero las pruebas unitarias deben probar el comportamiento, no la implementación. Los métodos privados son estrictamente parte de la implementación, por lo que la IMHO no debe ser probada.
Probamos métodos privados por inferencia, lo que significa que buscamos una cobertura total de exámenes de clase de al menos el 95%, pero nuestras pruebas solo tienen métodos públicos o internos. Para obtener la cobertura, debemos realizar varias llamadas al público / a las partes internas según los diferentes escenarios que puedan ocurrir. Esto hace que nuestras pruebas sean más estrictas en relación con el propósito del código que están probando.
La respuesta de Trumpi a la publicación que vinculaste es la mejor.
Pruebas unitarias que creo que son para probar métodos públicos. Sus métodos públicos utilizan sus métodos privados, por lo que indirectamente también se están probando.
Sí, hago pruebas de funciones privadas, porque aunque están probadas por sus métodos públicos, es bueno en TDD (Test Driven Design) probar la parte más pequeña de la aplicación. Pero las funciones privadas no son accesibles cuando estás en tu clase de unidad de prueba. Esto es lo que hacemos para probar nuestros métodos privados.
¿Por qué tenemos métodos privados?
Las funciones privadas existen principalmente en nuestra clase porque queremos crear código legible en nuestros métodos públicos. No queremos que el usuario de esta clase llame a estos métodos directamente, sino a través de nuestros métodos públicos. Además, no queremos cambiar su comportamiento al ampliar la clase (en caso de estar protegidos), por lo que es un proceso privado.
Cuando codificamos, usamos el diseño controlado por pruebas (TDD). Esto significa que a veces tropezamos con una parte de la funcionalidad que es privada y queremos probar. Las funciones privadas no se pueden probar en phpUnit, porque no podemos acceder a ellas en la clase de prueba (son privadas).
Pensamos que aquí hay 3 soluciones:
1. Puedes probar tus privados a través de tus métodos públicos.
Ventajas
- Prueba de unidad directa (no se necesitan ''hacks'')
Desventajas
- El programador necesita entender el método público, mientras que él solo quiere probar el método privado
- No estás probando la parte más pequeña comprobable de la aplicación
2. Si lo privado es tan importante, entonces tal vez sea un código para crear una nueva clase separada para él
Ventajas
- Puede refactorizar esto a una nueva clase, porque si es tan importante, otras clases también pueden necesitarlo.
- La unidad comprobable es ahora un método público, tan comprobable.
Desventajas
- No desea crear una clase si no es necesaria, y solo la utiliza la clase de la que proviene el método.
- Pérdida de rendimiento potencial debido a la sobrecarga agregada
3. Cambie el modificador de acceso a (final) protegido
Ventajas
- Estás probando la parte comprobable más pequeña de la aplicación. Cuando se utiliza Final Protegido, la función no será anulable (como un privado)
- Sin pérdida de rendimiento
- Sin gastos extras
Desventajas
- Estás cambiando un acceso privado a protegido, lo que significa que es accesible para sus hijos
- Aún necesitas una clase simulada en tu clase de prueba para usarla
Ejemplo
class Detective {
public function investigate() {}
private function sleepWithSuspect($suspect) {}
}
Altered version:
class Detective {
public function investigate() {}
final protected function sleepWithSuspect($suspect) {}
}
In Test class:
class Mock_Detective extends Detective {
public test_sleepWithSuspect($suspect)
{
//this is now accessible, but still not overridable!
$this->sleepWithSuspect($suspect);
}
}
Así que nuestra unidad de prueba ahora puede llamar a test_sleepWithSuspect para probar nuestra antigua función privada.
Si el método privado está bien definido (es decir, tiene una función que se puede probar y no está diseñada para cambiar con el tiempo), entonces sí. Pruebo todo lo que es verificable donde tiene sentido.
Por ejemplo, una biblioteca de cifrado puede ocultar el hecho de que realiza el cifrado de bloque con un método privado que cifra solo 8 bytes a la vez. Escribiría una prueba de unidad para eso; no está destinado a cambiar, aunque esté oculto, y si se rompe (debido a futuras mejoras de rendimiento, por ejemplo), quiero saber que es la función privada la que se rompió, no solo que se rompió una de las funciones públicas.
Acelera la depuración posterior.
-Adán
Si está desarrollando una prueba de manejo (TDD), probará sus métodos privados.
Si no prueba sus métodos privados, ¿cómo sabe que no se romperán?
Si su método privado no se prueba llamando a sus métodos públicos, ¿qué está haciendo? Estoy hablando en privado no protegido o amigo.
Tiendo a seguir los consejos de Dave Thomas y Andy Hunt en su libro Pragmatic Unit Testing :
En general, no desea romper ninguna encapsulación por el bien de la prueba (o como mamá solía decir, "¡no exponga sus secretos!"). La mayoría de las veces, debería poder probar una clase ejercitando sus métodos públicos. Si hay una funcionalidad importante que está oculta detrás del acceso privado o protegido, eso podría ser una señal de advertencia de que hay otra clase que está luchando por salir.
Pero a veces no puedo dejar de probar métodos privados porque me da la sensación de estar seguro de que estoy construyendo un programa completamente sólido.
Un punto principal es
Si probamos para asegurar la corrección de la lógica, y un método privado lleva una lógica, deberíamos probarlo. ¿No es así? Entonces, ¿por qué vamos a saltar eso?
Escribir pruebas basadas en la visibilidad de los métodos es una idea completamente irrelevante.
A la inversa
Por otro lado, llamar a un método privado fuera de la clase original es un problema principal. Y también hay limitaciones para burlarse de un método privado en algunas herramientas de burla. (Ej: Mockito )
Aunque hay algunas herramientas como Power Mock que lo admiten, es una operación peligrosa. La razón es que necesita hackear la JVM para lograrlo.
Una solución alternativa que se puede hacer es (si desea escribir casos de prueba para métodos privados)
Declara esos métodos privados como protegidos . Pero puede que no sea conveniente para varias situaciones.
Usted no debe Si sus métodos privados tienen suficiente complejidad que se deben probar, debe colocarlos en otra clase. Mantener alta cohesión , una clase debe tener un solo propósito. La interfaz pública de clase debería ser suficiente.
Nunca entiendo el concepto de prueba de unidad, pero ahora sé cuál es el objetivo.
Una prueba de unidad no es una prueba completa . Por lo tanto, no es un reemplazo para QA y prueba manual. El concepto de TDD en este aspecto es erróneo, ya que no se puede probar todo, incluidos los métodos privados, sino también los métodos que utilizan recursos (especialmente los recursos que no tenemos control). TDD está basando toda su calidad es algo que no se pudo lograr.
Una prueba de unidad es más una prueba de pivote Usted marca un pivote arbitrario y el resultado del pivote debería permanecer igual.
Absolutamente sí. Ese es el punto de la prueba de unidades, pruebas de unidades. El método privado es una unidad. Sin probar métodos privados TDD (Test Driven Development) sería imposible,
La respuesta a "¿Debo probar métodos privados?" es a veces". Normalmente deberías estar probando contra la interfaz de tus clases.
- Una de las razones es porque no necesita una cobertura doble para una función.
- Otra razón es que si cambia los métodos privados, tendrá que actualizar cada prueba para ellos, incluso si la interfaz de su objeto no ha cambiado en absoluto.
Aquí hay un ejemplo:
class Thing
def some_string
one + two
end
private
def one
''aaaa''
end
def two
''bbbb''
end
end
class RefactoredThing
def some_string
one + one_a + two + two_b
end
private
def one
''aa''
end
def one_a
''aa''
end
def two
''bb''
end
def two_b
''bb''
end
end
En RefactoredThing
ahora tiene 5 pruebas, 2 de las cuales era necesario actualizar para refactorización, pero la funcionalidad de su objeto no ha cambiado realmente. Entonces, digamos que las cosas son más complejas que eso y tiene algún método que define el orden de salida, como:
def some_string_positioner
if some case
elsif other case
elsif other case
elsif other case
else one more case
end
end
Esto no debe ser ejecutado por un usuario externo, pero su clase de encapsulación puede ser demasiado pesada para ejecutar tanta lógica una y otra vez. En este caso, tal vez prefiera extraer esto en una clase separada, darle a esa clase una interfaz y probarla.
Y, por último, digamos que su objeto principal es muy pesado, y el método es bastante pequeño y realmente necesita asegurarse de que la salida sea correcta. Estás pensando: "¡Tengo que probar este método privado!". ¿Tiene usted que tal vez pueda hacer su objeto más liviano pasando algo del trabajo pesado como parámetro de inicialización? Entonces puedes pasar algo más ligero y probar contra eso.
No, no deberías probar los métodos privados, why?y, además, el popular marco de burla, como Mockito, no proporciona soporte para probar métodos privados.
Si el método es lo suficientemente significativo o lo suficientemente complejo, normalmente lo haré "protegido" y lo probaré. Algunos métodos se dejarán privados y se probarán implícitamente como parte de las pruebas unitarias para los métodos públicos / protegidos.
Si encuentro que el método privado es enorme o complejo o lo suficientemente importante como para requerir sus propias pruebas, simplemente lo pongo en otra clase y lo hago público allí (Método Objeto). Entonces puedo probar fácilmente el método previamente privado pero ahora público que ahora vive en su propia clase.
Veo que muchas personas están en la misma línea de pensamiento: prueba a nivel público. ¿Pero no es eso lo que hace nuestro equipo de control de calidad? Ellos prueban la entrada y la salida esperada. Si como desarrolladores solo probamos los métodos públicos, simplemente estamos rehaciendo el trabajo de QA y no agregando ningún valor mediante "pruebas unitarias".