¿Se deben probar los valores de una enumeración usando pruebas unitarias?

13

Si tiene una enumeración solo con valores (no hay métodos como se podría hacer en Java), y esta enumeración es parte de la definición comercial del sistema, ¿debería una prueba de unidad de escritura?

Estaba pensando que deberían escribirse, incluso si pudieran parecer simples y redundantes, considero que lo que concierne a la especificación de negocios debe hacerse explícitamente en una prueba, ya sea con unit / integration / ui / etc. Pruebas o utilizando el sistema de tipos del lenguaje como método de prueba. Dado que los valores que debe tener una enumeración (por ejemplo, en Java), desde el punto de vista de la empresa, no se pueden probar utilizando el sistema de tipos, creo que debería haber una prueba de unidad para eso.

Esta pregunta no es similar a this ya que no aborda el mismo problema que el mío. En esa pregunta hay una función empresarial (savePeople) y la persona está preguntando acerca de la implementación interna (forEach). Allí, hay una capa intermedia de negocios (la función salvar personas) que encapsula el constructo del lenguaje (forEach). Aquí, la construcción del lenguaje (enum) es la que se usa para especificar el comportamiento desde un punto de vista empresarial.

En este caso, el detalle de la implementación coincide con la "verdadera naturaleza" de los datos, es decir: un conjunto (en el sentido matemático) de los valores. Podría decirse que podría usar un conjunto inmutable, pero los mismos valores deberían estar presentes allí. Si utiliza una matriz, debe hacer lo mismo para probar la lógica de negocios. Creo que el enigma aquí es el hecho de que la construcción del lenguaje coincide muy bien con la naturaleza de los datos. No estoy seguro de si me he explicado correctamente

    
pregunta IS1_SO 27.09.2017 - 15:47

9 respuestas

38
  

Si tiene una enumeración solo con valores (no hay métodos como se podría hacer en Java), y esta enumeración es parte de la definición comercial del sistema, ¿debería una prueba de unidad de escritura?

No, son solo estado.

Fundamentalmente, el hecho de que esté utilizando una enumeración es un detalle de implementación ; ese es el tipo de cosa que quizás quieras refactorizar en un diseño diferente.

La comprobación de las enumeraciones para ver si está completa es análoga a la prueba de que todos los enteros representables están presentes.

Sin embargo, probar los comportamientos que admiten las enumeraciones es una buena idea. En otras palabras, si comienza desde un conjunto de pruebas aprobadas y comenta un valor de enumeración único, entonces al menos una prueba debería fallar (los errores de compilación se consideran fallas).

    
respondido por el VoiceOfUnreason 27.09.2017 - 16:27
17

No prueba una enumeración declaración . Puede probar si la entrada / salida de la función tiene los valores de enumeración esperados. Ejemplo:

enum Parity {
    Even,
    Odd
}

Parity GetParity(int x) { ... }

Usted no escribe pruebas y luego enumeración Parity define los nombres Even y Odd . Tal prueba sería inútil ya que simplemente estaría repitiendo lo que ya está establecido en el código. Decir lo mismo dos veces no lo hace más correcto.

Usted do escribe pruebas verificando GetParity say devolverá Even para 0, Odd para 1 y así sucesivamente. Esto es valioso porque no está repitiendo el código, está verificando el comportamiento del código, independientemente de la implementación. Si el código dentro de GetParity se reescribiera completamente, las pruebas seguirían siendo válidas. De hecho, los principales beneficios de las pruebas unitarias son que te dan la libertad de volver a escribir y refactorizar el código de forma segura, al garantizar que el código siga funcionando como se esperaba.

Pero si tiene una prueba que asegura que una enumeración declaración define los nombres esperados, entonces cualquier cambio que realice en la enumeración en el futuro también requerirá que cambie la prueba. Esto significa que no solo es el doble de trabajo, también significa que se pierde cualquier beneficio de la prueba de la unidad. Si tiene que cambiar el código y probar al mismo tiempo , entonces no hay ninguna protección contra la introducción de errores.

    
respondido por el JacquesB 27.09.2017 - 16:53
11

No, una prueba que comprueba que una enumeración contiene todos los valores válidos y nada más esencialmente repite la declaración de la enumeración. Solo estaría probando que el lenguaje implementa correctamente la construcción enum, que es una prueba sin sentido.

Dicho esto, debe probar el comportamiento que depende de los valores de enumeración. Por ejemplo, si está utilizando los valores de enumeración para serializar las entidades a json o lo que sea, o si almacena los valores en una base de datos, debe probar el comportamiento para todos los valores de la enumeración. De esa manera, si se modifica la enumeración, al menos una de las pruebas debería fallar. En cualquier caso, lo que estaría probando es el comportamiento en torno a su enumeración, no la declaración de enumeración en sí misma.

    
respondido por el jesm00 27.09.2017 - 17:03
8

Si existe el riesgo de que el cambio de la enumeración rompa su código, entonces seguro, cualquier cosa con el atributo [Flags] en C # sería un buen caso, porque agregar un valor entre 2 y 4 (3) sería 1 y 2 En lugar de un elemento discreto.

Es una capa de protección.

Debería considerar tener un código de práctica enumeración con el que todos los desarrolladores estén familiarizados. No confiar en las representaciones textuales de la enumeración es una común, pero esto podría entrar en conflicto con sus directrices de serialización.

He visto a personas "corregir" el uso de mayúsculas en las entradas de enumeración, ordenarlas alfabéticamente o por algún otro grupo lógico, todo lo cual rompió otros bits de código incorrecto.

    
respondido por el Ian 27.09.2017 - 16:19
2

Su código debería funcionar correctamente, independientemente de los valores reales de una enumeración. Si ese es el caso, entonces no se necesitan pruebas unitarias.

Pero es posible que tenga un código donde cambiar un valor de enumeración rompa cosas. Por ejemplo, si un valor de enumeración se almacena en un archivo externo, y después de cambiar el valor de enum, leer el archivo externo dará un resultado incorrecto. En ese caso, tendrá un GRAN comentario cerca de la enumeración que le advertirá a cualquiera que no modifique ningún valor, y es muy posible que escriba una prueba unitaria que verifique los valores numéricos.

    
respondido por el gnasher729 28.09.2017 - 00:12
1

En general, solo comprobar que una enumeración tiene una lista de valores codificada no tiene mucho valor, como dicen otras respuestas, porque entonces solo necesitas actualizar la prueba y la enumeración juntos.

Una vez tuve el caso de que un módulo usaba tipos de enumeraciones de otros dos módulos y los asignaba entre ellos. (Uno de los enumerados tenía lógica adicional, el otro era para el acceso a la base de datos, ambos tenían dependencias que deberían estar aisladas entre sí).

En este caso, agregué una prueba (en el módulo de asignación) que verificó que todas las entradas de enumeración en la enumeración de origen también existen en la enumeración de destino (y, por lo tanto, que la asignación siempre funcionaría). (Para algunos casos también verifiqué al revés).

De esta manera, cuando alguien agregó una entrada de enumeración a una de las enumeraciones y olvidó agregar la entrada correspondiente a la otra, una prueba comenzó a fallar.

    
respondido por el Paŭlo Ebermann 27.09.2017 - 22:18
1

Las enumeraciones son simplemente tipos finitos, con nombres personalizados (con suerte significativos). Es posible que una enumeración solo tenga un valor, como void que contenga solo null (algunos idiomas lo llaman unit y usan el nombre void para una enumeración con elementos no ). Puede tener dos valores, como bool que tiene false y true . Puede tener tres, como colourChannel con red , green y blue . Y así sucesivamente.

Si dos enumeraciones tienen el mismo número de valores, entonces son "isomorfos"; es decir, si cambiamos todos los nombres sistemáticamente, entonces podemos usar uno en lugar de otro y nuestro programa no se comportará de manera diferente. ¡En particular, nuestras pruebas no se comportarán de manera diferente!

Por ejemplo, result que contiene win / lose / draw es isomorfo al colourChannel anterior, ya que podemos reemplazar, por ejemplo, colourChannel con result , red con win , green con lose y blue con draw , y siempre que lo hagamos everywhere (productores y consumidores, analizadores y serializadores, entradas de base de datos, archivos de registro, etc.) entonces no habrá cambios en nuestro programa. Cualquier " colourChannel pruebas" que escribimos todavía pasará, ¡aunque ya no haya colourChannel !

Además, si una enumeración contiene más de un valor, siempre podemos reorganizar esos valores para obtener una nueva enumeración con el mismo número de valores. Dado que el número de valores no ha cambiado, el nuevo acuerdo es isomorfo al anterior, y por lo tanto podríamos cambiar todos los nombres y nuestras pruebas seguirían pasando (tenga en cuenta que no podemos simplemente cambie la definición; también debemos cambiar todos los sitios de uso).

Lo que esto significa es que, en lo que respecta a la máquina, las enumeraciones son "nombres distinguibles" y nada más . Lo único que podemos hacer con una enumeración es dividir si dos valores son iguales (por ejemplo, red / red ) o diferentes (por ejemplo, red / blue ). Así que eso es lo único que puede hacer una "prueba de unidad", por ejemplo,

(  red == red  ) || throw TestFailure;
(green == green) || throw TestFailure;
( blue == blue ) || throw TestFailure;
(  red != green) || throw TestFailure;
(  red != blue ) || throw TestFailure;
...

Como dice @ jesm00, dicha prueba está verificando la implementación de lenguaje en lugar de su programa. Estas pruebas nunca son una buena idea: incluso si no confías en la implementación del lenguaje, deberías probarlo desde fuera , ¡ya que no se puede confiar en que las pruebas se ejecuten correctamente!

Así que esa es la teoría; ¿Qué pasa con la práctica? El principal problema con esta caracterización de enumeraciones es que los programas del "mundo real" rara vez son autocontenidos: tenemos versiones heredadas, implementaciones remotas / integradas, datos históricos, copias de seguridad, bases de datos en vivo, etc., por lo que nunca podemos realmente "cambiar" todas las apariciones de un nombre sin perder algunos usos.

Sin embargo, tales cosas no son la 'responsabilidad' de la enumeración en sí misma: cambiar una enumeración podría interrumpir la comunicación con un sistema remoto, pero a la inversa, podemos arreglar este problema al cambiar una enumeración.

En tales escenarios, la enumeración es una pista falsa: ¿qué pasa si un sistema necesita que sea de esta manera , y otro necesita que sea de esa manera ? No pueden ser ambas cosas, ¡no importa cuántas pruebas escribamos! El verdadero culpable aquí es la interfaz de entrada / salida, que debería producir / consumir formatos bien definidos en lugar de "cualquiera que sea el número entero que interprete las elecciones". Así que la solución real es probar las interfaces de E / S : con pruebas unitarias para verificar que está analizando / imprimiendo el formato esperado, y con pruebas de integración para verificar que el formato sea realmente aceptado por el otro lado .

Todavía podemos preguntarnos si la enumeración se está 'ejerciendo lo suficientemente bien', pero en este caso la enumeración es nuevamente una pista falsa. Lo que realmente nos preocupa es el propio conjunto de pruebas . Podemos ganar confianza aquí de un par de maneras:

  • La cobertura del código puede decirnos si la variedad de valores de enumeración que proviene del conjunto de pruebas es suficiente para activar las diversas ramas del código. Si no, podemos agregar pruebas que activen las ramas descubiertas, o generar una variedad más amplia de enumeraciones en las pruebas existentes.
  • La verificación de propiedades nos puede decir si la variedad de sucursales en el código es suficiente para manejar las posibilidades de tiempo de ejecución. Por ejemplo, si el código solo maneja red , y solo probamos con red , entonces tenemos una cobertura del 100%. Un verificador de propiedades (intentará) generará contraejemplos de nuestras aserciones, como generar los valores green y blue que olvidamos probar.
  • Las pruebas de mutación pueden indicar si nuestras afirmaciones en realidad comprueban la enumeración, en lugar de seguir las ramas e ignorar sus diferencias.
respondido por el Warbo 28.09.2017 - 14:59
0

Se espera que pruebe el comportamiento observable de su código, los efectos de las llamadas de método / función en el estado observable. Mientras el código haga lo correcto, está bien, no necesita probar nada más.

No necesita afirmar explícitamente que un tipo de enumeración tiene las entradas que espera, al igual que no afirma explícitamente que una clase existe realmente o que tiene los métodos y atributos que espera.

En realidad, al probar el comportamiento, usted está afirmando implícitamente que las clases, los métodos y los valores involucrados en la prueba existen, por lo tanto, no es necesario que lo afirme explícitamente.

Tenga en cuenta que no necesita nombres significativos para que su código haga lo correcto, eso es solo una comodidad para las personas que leen su código. Podrías hacer que tu código funcione con valores de enumeración como foo , bar ... y métodos como frobnicate() .

    
respondido por el Goyo 27.09.2017 - 20:37
0

No. Las pruebas unitarias son para unidades de prueba.

  

En la programación orientada a objetos, una unidad es a menudo una interfaz completa, como una clase, pero podría ser un método individual.

enlace

Una prueba automatizada para una enumeración declarada probaría la integridad del lenguaje y la plataforma en la que se ejecuta en lugar de la lógica en el código creado por el desarrollador. No tendría ningún propósito útil, incluida la documentación, ya que el código que declara la enumeración sirve como documentación, así como el código que lo probaría.

    
respondido por el digimunk 28.09.2017 - 16:36

Lea otras preguntas en las etiquetas