una turing test sirve que prueba pasa para objetivos objeciones metodo maquina juego imitacion historia c# unit-testing state-machines mspec

c# - turing - ¿Cuáles son algunas estrategias para probar máquinas grandes de estado?



test de turing para que sirve (9)

Heredé una máquina de estados grande y bastante compleja. Tiene 31 estados posibles, todos son realmente necesarios (proceso de grandes empresas). Tiene las siguientes entradas:

  • Enumeración: Estado actual (entonces 0 -> 30)
  • Enumeración: fuente (actualmente solo 2 entradas)
  • Booleano: solicitud
  • Booleano: Tipo
  • Enumeración: Estado (3 estados)
  • Enumeración: Manejo (3 estados)
  • Booleano: Completado

Romperlo en máquinas de estado separadas no parece factible, ya que cada estado es distinto. Escribí pruebas para las entradas más comunes, con una prueba por entrada, todas las entradas constantes, excepto el Estado.

[Subject("Application Process States")] public class When_state_is_meeting2Requested : AppProcessBase { Establish context = () => { //Setup.... }; Because of = () => process.Load(jas, vac); It Current_node_should_be_meeting2Requested = () => process.CurrentNode.ShouldBeOfType<meetingRequestedNode>(); It Can_move_to_clientDeclined = () => Check(process, process.clientDeclined); It Can_move_to_meeting1Arranged = () => Check(process, process.meeting1Arranged); It Can_move_to_meeting2Arranged = () => Check(process, process.meeting2Arranged); It Can_move_to_Reject = () => Check(process, process.Reject); It Cannot_move_to_any_other_state = () => AllOthersFalse(process); }

Nadie está completamente seguro de cuál debe ser la salida para cada estado y conjunto de entradas. He empezado a escribir pruebas para ello. Sin embargo, tendré que escribir algo así como 4320 pruebas (30 * 2 * 2 * 2 * 3 * 3 * 2).

¿Qué sugerencias tienes para probar máquinas de estado?

Edición: Estoy jugando con todas las sugerencias y marcaré una respuesta cuando encuentre la que funcione mejor.


¿Cuántas pruebas crees que se necesitan para probar completamente la función sum (int a, int b)? En c # sería algo así como 18446744056529682436 pruebas ... Mucho peor que en tu caso.

Sugeriría lo siguiente:

  1. Prueba la mayoría de las situaciones posibles, condiciones de contorno.
  2. Pruebe algunas partes críticas de su SUT por separado.
  3. Agregue los casos de prueba cuando los errores encontrados por QA o en producción.

En este caso particular, la mejor manera es probar cómo el sistema cambia de un estado a otro. Cree DSL para probar la máquina de estados e implementar los casos de uso más frecuentes al usarla. Por ejemplo:

Start .UploadDocument("name1") .SendDocumentOnReviewTo("user1") .Review() .RejectWithComment("Not enough details") .AssertIsCompleted()

El ejemplo de creación de pruebas simples para flujos está aquí: http://slmoloch.blogspot.com/2009/12/design-of-selenium-tests-for-aspnet_09.html


Había construido una máquina de estados finitos para un equipo médico. El FSM era configurable a través de un formato XML que había definido.

Para definir una máquina de estado, uno tiene que confiar en la experiencia en diseños de circuitos digitales al usar mapas de estado,

Tienes que usar lo que yo llamo un mapa de transición de Turnpike. En la costa este de los Estados Unidos, la mayoría de las autopistas son apodadas autopistas. Las autoridades de Turnpike emiten un mapa de precios de peaje de Turnpike. Si una sección de peaje tuviera 50 salidas, el mapa de precios tendría una tabla de 50 filas x 50cols, que enumera las salidas exhaustivamente como filas y columnas. Para averiguar el costo del peaje para ingresar a la salida 20 y salir de la salida 30, simplemente busque la intersección de la fila 20 y la columna 30.

Para una máquina de estados de 30 estados, el mapa de transición de Turnpike sería una matriz de 30 x 30 que enumera todos los 30 estados posibles fila y columna. Decidamos que las filas sean estados ACTUALES y que las columnas sean estados SIGUIENTES.

Cada celda que se intersecta enumera el "precio" de la transición de un estado ACTUAL (fila) a un estado SIGUIENTE (col). Sin embargo, en lugar de un solo valor $, la celda se referiría a una fila en la tabla de Entradas, que podríamos denominar como la identificación de transición.

En el equipo médico que desarrolló el FSM, había entradas que son Cadena, enumeraciones, int, etc. La tabla de Entradas enumeró estos estímulos de entrada por columnas.

Para construir la tabla de Entradas, escribiría una rutina simple para enumerar todas las combinaciones posibles de entradas. Pero la mesa sería enorme. En su caso, la tabla tendría 4320 filas y, por lo tanto, 4320 id de transición. Pero no es una tabla tediosa porque generaste la tabla programáticamente. En mi caso, escribí un JSP simple para listar la tabla de entrada de las transiciones (y la tabla de autopistas) en el navegador o descargarlas como csv para mostrarlas en MS Excel.

Hay dos direcciones para construir estas dos tablas.

  1. la dirección de diseño, donde se construye la tabla de la autopista de peaje todas las transiciones posibles, borrando las transiciones no alcanzables. Luego construya la tabla de Entradas de todas las entradas esperadas para cada transición alcanzable, con el número de fila como identificación de transición. Cada ID de transición se transcribe en la celda respectiva del mapa de transición de Turnpike. Sin embargo, dado que el FSM es una matriz dispersa, no todas las identificaciones de transición se utilizarán en las celdas del mapa de transición de Turnpike. Además, una identificación de transición se puede usar muchas veces porque las mismas condiciones de transición se pueden aplicar a más de un par de cambios de estado.

  2. la dirección de la prueba es inversa, donde se construye la tabla de Entradas. Tienes que escribir una rutina general para la prueba de transición exhaustiva.
    La rutina primero leería una tabla de secuencia de transición para llevar la máquina de estados a un estado de punto de entrada para iniciar un ciclo de prueba. En cada estado actual, está preparado para ejecutarse a través de todos los 4320 id de transición. En cada fila de estados ACTUALES en el mapa de transición de Turnpike, habría un número limitado de columnas estados NEXT válidos.

Usted desearía que la rutina realice un ciclo a través de las 4320 filas de entradas que lee de la tabla de Entradas, para garantizar que las identificaciones de transición no utilizadas no tengan efecto en un estado ACTUAL. Quiere probar que todas las identificaciones de transición efectivas son transiciones válidas.

Pero no puede, porque una vez que se bombea una transición efectiva, cambiará el estado de la máquina a un estado SIGUIENTE e impedirá que complete la prueba del resto de los identificadores de transición en ese estado ACTUAL anterior. Una vez que la máquina cambia de estado, debe comenzar a probar nuevamente desde la ID de transición 0.

Las rutas de transición pueden ser cíclicas o irreversibles o tener una combinación de secciones cíclicas e irreversibles a lo largo de la ruta.

Dentro de su rutina de prueba, necesita un registro para cada estado para memorizar la última identificación de transición introducida en ese estado. Cada vez que la prueba alcanza un ID de transición efectivo, ese ID de transición se deja en ese registro. Para que cuando complete un ciclo y regrese a un estado ya atravesado, comience a iterar en la siguiente identificación de transición mayor que la almacenada en el registro.

Su rutina tendría que ocuparse de las secciones irreversibles de una ruta de transición, cuando una máquina llega a un estado final, se reinicia la prueba desde el estado del punto de entrada, reiterando las 4320 entradas de la siguiente ID de transición mayor que la almacenada. para un estado. De esta manera, podrá descubrir exhaustivamente todas las rutas de transición posibles de la máquina.

Afortunadamente, las FSM son matrices dispersas de transiciones efectivas porque las pruebas exhaustivas no consumirían la combinación completa de la cantidad de ids de transición x la cantidad de estados posibles al cuadrado. Sin embargo, la dificultad se presenta si está lidiando con un FSM heredado donde los estados visuales o de temperatura no se pueden enviar al sistema de prueba, donde debe monitorear visualmente cada estado. Eso sería feo, pero aún pasamos dos semanas probando adicionalmente el equipo visualmente pasando solo por las transiciones efectivas.

Es posible que no necesite una tabla de secuencia de transición (para cada estado de punto de entrada que debe leer la rutina de prueba para llevar la máquina a un punto de entrada deseado) si su FSM le permite alcanzar un punto de entrada con un simple restablecimiento y la aplicación de una identificación de transición simplemente lo haría. a un estado de punto de entrada. Sin embargo, tener una rutina capaz de leer una tabla de secuencia de transición es útil porque, con frecuencia, debería ingresar a la red estatal e iniciar sus pruebas desde allí.

Debe familiarizarse con el uso de los mapas de transición y de estado, ya que es muy útil para detectar todos los estados posibles e indocumentados de una máquina y entrevistar a los usuarios si realmente deseaban que estuvieran atenuados (las transiciones se hicieron ineficaces y los estados se hicieron inalcanzables).

La ventaja que tenía era que era una nueva pieza de equipo y tuve la opción de diseñar el controlador de la máquina de estado para leer archivos xml, lo que significa que podía cambiar el comportamiento de la máquina de estado de cualquier manera que quisiera, de hecho, el cliente quería y Pude asegurar que las identificaciones de transición no utilizadas eran realmente ineficaces.

Para la lista en java del controlador de máquina de estado finito http://code.google.com/p/synthfuljava/source/browse/#svn/trunk/xml/org/synthful . Rutinas de prueba no incluidas.


La fuerza bruta con pruebas de cobertura parece ser un comienzo.


No puedo pensar en una manera fácil de hacer una prueba de este tipo de FSM sin ser realmente pedante y empleando pruebas, utilizando técnicas de aprendizaje automático o fuerza bruta.

Fuerza bruta: escriba algo que genere todos los 4320 casos de prueba de alguna manera declarativa con datos en su mayoría incorrectos. Recomendaría poner esto en un archivo CSV y luego usar algo como las pruebas parametéricas de NUnits para cargar todos los casos de prueba. Ahora la mayoría de estos casos de prueba fallarán, por lo que tendrá que actualizar el archivo declarativo manualmente para que sea correcto y tomar solo una muestra de los casos de prueba para corregirlos.

Técnica de aprendizaje automático: puede emplear algunas máquinas Vector o algoritmos / heurísticas MDA para tratar de aprender sobre la muestra que tomó de lo que mencionamos anteriormente y enseñar a su programa de ML su FSM. Luego ejecute el algoritmo en todas las 4320 entradas y vea dónde las dos no están de acuerdo.


Podría considerar la posibilidad de investigar las pruebas basadas en modelos . Hay algunas herramientas disponibles para ayudar con la generación de pruebas en situaciones como esta. Por lo general recomiendo MBT .


Prueba basada en los requisitos. Si se requiere un cierto estado para pasar a otro estado determinado cuando Completado es verdadero, entonces escriba una prueba que recorra automáticamente todas las combinaciones de las otras entradas (esto debería ser un par de bucles) para probar que las otras entradas son correctamente ignorado Debería terminar con una prueba para cada arco de transición, que estimaría que estaría en algún lugar del orden de 100 o 150 pruebas, no de 4000.



Veo el problema, pero definitivamente intentaría dividir la lógica.

El área del gran problema en mis ojos es:

  • Tiene 31 estados posibles para estar.
  • Tiene las siguientes entradas:
    • Enumeración: Estado actual (entonces 0 -> 30)
    • Enumeración: fuente (actualmente solo 2 entradas)
    • Booleano: solicitud
    • Booleano: tipo
    • Enumeración: Estado (3 estados)
    • Enumeración: Manejo (3 estados)
    • Booleano: Completado

Hay demasiadas cosas en marcha. La entrada hace que el código sea difícil de probar. Usted ha dicho que sería doloroso dividir esto en áreas más manejables, pero es igual o más doloroso probar esta lógica en marcha. En su caso, cada prueba de unidad cubre demasiado terreno.

Esta pregunta que hice acerca de probar métodos grandes es similar en naturaleza, encontré que mis unidades eran simplemente demasiado grandes. Aún terminarás con muchas pruebas, pero serán más pequeñas y más manejables, cubriendo menos terreno. Sin embargo, esto solo puede ser algo bueno.

Prueba del código heredado

Echa un vistazo a Pex . Usted afirma que heredó este código, por lo que esto no es realmente un desarrollo controlado por pruebas. Simplemente quieres pruebas de unidad para cubrir cada aspecto. Esto es algo bueno, ya que cualquier trabajo adicional será validado. Personalmente todavía no he usado Pex correctamente, sin embargo, me sorprendió el video que vi. Esencialmente generará pruebas unitarias basadas en la entrada, que en este caso sería la propia máquina de estados finitos. Generará casos de prueba en los que no habrá pensado lo suficiente. Por supuesto, esto no es TDD, pero en este escenario, probar el código heredado, debería ser ideal.

Una vez que tenga su cobertura de prueba, puede comenzar a refactorizar o agregar nuevas funciones con la seguridad de una buena cobertura de prueba para asegurarse de que no rompe ninguna funcionalidad existente.


Pruebas de todos los pares

Para restringir la cantidad de combinaciones a probar y estar razonablemente seguro de que tiene cubiertas las combinaciones más importantes, debe echar un vistazo a las pruebas de todos los pares.

El razonamiento detrás de la prueba de todos los pares es el siguiente: los errores más simples en un programa generalmente se activan mediante un solo parámetro de entrada. La siguiente categoría más simple de errores consiste en aquellos que dependen de las interacciones entre pares de parámetros, que pueden detectarse con pruebas de todos los pares.1 Los errores que involucran interacciones entre tres o más parámetros son progresivamente menos comunes2, mientras que al mismo tiempo son cada vez más caros Encontrar mediante pruebas exhaustivas, que tiene como límite la prueba exhaustiva de todas las entradas posibles.

Vea también una respuesta anterior aquí (conector descarado) para obtener información adicional y enlaces a ambos pares y pict como herramienta.

Ejemplo de archivo modelo pict

El modelo dado genera 93 cajas de prueba, que cubren todos los pares de parámetros de entrada.

# # This is a PICT model for testing a complex state machine at work # CurrentState :0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 Source :1,2 Request :True, False Type :True, False Status :State1, State2, State3 Handling :State1, State2, State3 Completed :True,False # # One can add constraints to the model to exclude impossible # combinations if needed. # # For example: # IF [Completed]="True" THEN CurrentState>15; # # # This is the PICT output of "pict ComplexStateMachine.pict /s /r1" # # Combinations: 515 # Generated tests: 93