Hasta ahora he evitado la pesadilla que está probando el código de subprocesos múltiples, ya que parece demasiado campo de minas. Me gustaría preguntar cómo la gente ha probado el código que se basa en subprocesos para una ejecución exitosa, o cómo las personas han intentado probar ese tipo de problemas que solo aparecen cuando dos subprocesos interactúan de una manera determinada.
Este parece ser un problema realmente clave para los programadores de hoy, sería útil aunar nuestros conocimientos en este caso.
Respuestas:
Mira, no hay una manera fácil de hacer esto. Estoy trabajando en un proyecto que es inherentemente multiproceso. Los eventos provienen del sistema operativo y tengo que procesarlos simultáneamente.
La forma más sencilla de lidiar con la prueba de código de aplicación complejo y multiproceso es esta: si es demasiado complejo para probarlo, lo está haciendo mal. Si tiene una única instancia que tiene varios subprocesos que actúan sobre ella, y no puede probar situaciones en las que estos subprocesos se superponen, entonces su diseño debe rehacerse. Es tan simple y tan complejo como esto.
Hay muchas formas de programar para subprocesos múltiples que evitan que los subprocesos se ejecuten a través de instancias al mismo tiempo. Lo más simple es hacer que todos sus objetos sean inmutables. Por supuesto, eso no suele ser posible. Por lo tanto, debe identificar esos lugares en su diseño donde los hilos interactúan con la misma instancia y reducir el número de esos lugares. Al hacer esto, aísla algunas clases en las que realmente se produce el subprocesamiento múltiple, lo que reduce la complejidad general de probar su sistema.
Pero debes darte cuenta de que, incluso al hacer esto, aún no puedes probar todas las situaciones en las que dos hilos se cruzan. Para hacer eso, tendría que ejecutar dos hilos simultáneamente en la misma prueba, luego controlar exactamente qué líneas están ejecutando en un momento dado. Lo mejor que puedes hacer es simular esta situación. Pero esto puede requerir que codifique específicamente para las pruebas, y eso es, en el mejor de los casos, medio paso hacia una solución verdadera.
Probablemente la mejor manera de probar el código para problemas de subprocesos es a través del análisis estático del código. Si su código enhebrado no sigue un conjunto finito de patrones seguros para subprocesos, entonces podría tener un problema. Creo que el Análisis de código en VS contiene cierto conocimiento de subprocesos, pero probablemente no mucho.
Mire, como están las cosas actualmente (y probablemente lo harán en un buen momento), la mejor manera de probar aplicaciones multiproceso es reducir la complejidad del código roscado tanto como sea posible. Minimice las áreas donde los hilos interactúan, pruebe lo mejor posible y use el análisis de código para identificar áreas peligrosas.
fuente
Ha pasado un tiempo cuando se publicó esta pregunta, pero aún no se ha respondido ...
La respuesta de kleolb02 es buena. Intentaré entrar en más detalles.
Hay una manera, que practico para el código C #. Para las pruebas unitarias, debe poder programar pruebas reproducibles , que es el mayor desafío en el código multiproceso. Entonces, mi respuesta apunta a forzar el código asíncrono en un arnés de prueba, que funciona de forma sincrónica .
Es una idea del libro de Gerard Meszardos " Patrones de prueba xUnit " y se llama "Objeto humilde" (p. 695): debe separar el código lógico central y todo lo que huela a código asíncrono entre sí. Esto daría como resultado una clase para la lógica central, que funciona sincrónicamente .
Esto lo coloca en la posición de probar el código lógico central de forma síncrona . Usted tiene control absoluto sobre el tiempo de las llamadas que está haciendo en la lógica central y, por lo tanto, puede realizar pruebas reproducibles . Y esta es su ganancia al separar la lógica central y la lógica asincrónica.
Esta lógica central necesita ser ajustada por otra clase, que es responsable de recibir llamadas a la lógica central de forma asincrónica y delega estas llamadas a la lógica central. El código de producción solo accederá a la lógica central a través de esa clase. Debido a que esta clase solo debería delegar llamadas, es una clase muy "tonta" sin mucha lógica. Por lo tanto, puede mantener sus pruebas unitarias para esta clase de trabajo asíncrona como mínimo.
Cualquier cosa por encima de eso (prueba de interacción entre clases) son pruebas de componentes. También en este caso, debería poder tener un control absoluto sobre el tiempo, si se adhiere al patrón "Objeto Humilde".
fuente
Duro uno de hecho! En mis pruebas unitarias (C ++), he dividido esto en varias categorías a lo largo de las líneas del patrón de concurrencia utilizado:
Pruebas unitarias para clases que operan en un solo subproceso y no son compatibles con subprocesos: fácil, pruebe como de costumbre.
Pruebas unitarias para objetos de Monitor (aquellos que ejecutan métodos sincronizados en el hilo de control de las personas que llaman) que exponen una API pública sincronizada - instancian múltiples hilos simulados que ejercen la API. Construir escenarios que ejerzan condiciones internas del objeto pasivo. Incluya una prueba de ejecución más larga que básicamente lo supere en múltiples subprocesos durante un largo período de tiempo. Esto no es científico, lo sé, pero genera confianza.
Pruebas unitarias para objetos activos (aquellos que encapsulan su propio hilo o hilos de control) - similar al # 2 anterior con variaciones dependiendo del diseño de la clase. La API pública puede estar bloqueando o no bloqueando, las personas que llaman pueden obtener futuros, los datos pueden llegar a las colas o deben retirarse. Hay muchas combinaciones posibles aquí; caja blanca de distancia. Todavía requiere múltiples hilos simulados para hacer llamadas al objeto bajo prueba.
Como un aparte:
En la capacitación interna para desarrolladores que hago, enseño los Pilares de la concurrencia y estos dos patrones como marco principal para pensar y descomponer los problemas de concurrencia. Obviamente, existen conceptos más avanzados, pero he descubierto que este conjunto de conceptos básicos ayuda a mantener a los ingenieros fuera de la sopa. También conduce a un código que es más comprobable por unidad, como se describió anteriormente.
fuente
Me he enfrentado a este problema varias veces en los últimos años al escribir código de manejo de hilos para varios proyectos. Proporciono una respuesta tardía porque la mayoría de las otras respuestas, aunque ofrecen alternativas, en realidad no responden la pregunta sobre las pruebas. Mi respuesta se dirige a los casos donde no hay alternativa al código multiproceso; Cubro los problemas de diseño del código para completarlos, pero también analizo las pruebas unitarias.
Escribir código multiproceso comprobable
Lo primero que debe hacer es separar su código de manejo de subprocesos de producción de todo el código que realiza el procesamiento de datos real. De esa manera, el procesamiento de datos se puede probar como código de subproceso único, y lo único que hace el código multiproceso es coordinar subprocesos.
La segunda cosa para recordar es que los errores en el código multiproceso son probabilísticos; Los errores que se manifiestan con menos frecuencia son los errores que se infiltrarán en la producción, serán difíciles de reproducir incluso en la producción y, por lo tanto, causarán los mayores problemas. Por esta razón, el enfoque de codificación estándar de escribir el código rápidamente y luego depurarlo hasta que funcione es una mala idea para el código multiproceso; dará como resultado un código donde se arreglan los errores fáciles y los errores peligrosos todavía están allí.
En cambio, al escribir código multiproceso, debe escribir el código con la actitud de que va a evitar escribir los errores en primer lugar. Si ha eliminado correctamente el código de procesamiento de datos, el código de manejo de subprocesos debe ser lo suficientemente pequeño, preferiblemente unas pocas líneas, en el peor de los casos, unas pocas docenas de líneas, de modo que tenga la posibilidad de escribirlo sin escribir un error, y ciertamente sin escribir muchos errores , si comprende el enhebrado, tómese su tiempo y tenga cuidado.
Escritura de pruebas unitarias para código multiproceso
Una vez que el código multiproceso se escribe con el mayor cuidado posible, todavía vale la pena escribir pruebas para ese código. El propósito principal de las pruebas no es tanto para detectar errores de condición de carrera altamente dependientes del tiempo, es imposible probar repetidamente tales condiciones de carrera, sino probar que su estrategia de bloqueo para prevenir tales errores permite que múltiples hilos interactúen según lo previsto .
Para probar correctamente el comportamiento correcto de bloqueo, una prueba debe iniciar varios subprocesos. Para que la prueba sea repetible, queremos que las interacciones entre los hilos sucedan en un orden predecible. No queremos sincronizar externamente los hilos en la prueba, porque eso enmascarará los errores que podrían ocurrir en la producción donde los hilos no están sincronizados externamente. Eso deja el uso de retrasos de sincronización para la sincronización de subprocesos, que es la técnica que he utilizado con éxito cada vez que tuve que escribir pruebas de código multiproceso.
Si los retrasos son demasiado cortos, entonces la prueba se vuelve frágil, porque las pequeñas diferencias de tiempo, por ejemplo, entre diferentes máquinas en las que se pueden ejecutar las pruebas, pueden hacer que el tiempo se desactive y la prueba falle. Lo que generalmente he hecho es comenzar con demoras que causan fallas en la prueba, aumentar las demoras para que la prueba pase de manera confiable en mi máquina de desarrollo y luego duplicar las demoras más allá de eso para que la prueba tenga una buena posibilidad de pasar en otras máquinas. Esto significa que la prueba tomará una cantidad de tiempo macroscópica, aunque en mi experiencia, el diseño cuidadoso de la prueba puede limitar ese tiempo a no más de una docena de segundos. Dado que no debería tener muchos lugares que requieran código de coordinación de subprocesos en su aplicación, eso debería ser aceptable para su conjunto de pruebas.
Finalmente, realice un seguimiento de la cantidad de errores detectados por su prueba. Si su prueba tiene una cobertura de código del 80%, se espera que detecte alrededor del 80% de sus errores. Si su prueba está bien diseñada pero no encuentra errores, existe una posibilidad razonable de que no tenga errores adicionales que solo aparecerán en la producción. Si la prueba detecta uno o dos errores, aún puede tener suerte. Más allá de eso, y es posible que desee considerar una revisión cuidadosa o incluso una reescritura completa de su código de manejo de subprocesos, ya que es probable que el código aún contenga errores ocultos que serán muy difíciles de encontrar hasta que el código esté en producción, y muy difícil de arreglar entonces.
fuente
También tuve serios problemas al probar código multiproceso. Luego encontré una solución realmente genial en "xUnit Test Patterns" de Gerard Meszaros. El patrón que describe se llama objeto humilde .
Básicamente describe cómo puede extraer la lógica en un componente separado y fácil de probar que está desacoplado de su entorno. Después de probar esta lógica, puede probar el comportamiento complicado (subprocesamiento múltiple, ejecución asincrónica, etc.)
fuente
Hay algunas herramientas que son bastante buenas. Aquí hay un resumen de algunos de los Java.
Algunas buenas herramientas de análisis estático incluyen FindBugs (da algunas sugerencias útiles), JLint , Java Pathfinder (JPF y JPF2) y Bogor .
MultithreadedTC es una herramienta de análisis dinámico bastante buena (integrada en JUnit) donde tiene que configurar sus propios casos de prueba.
ConTest de IBM Research es interesante. Instrumenta su código insertando todo tipo de comportamientos de modificación de subprocesos (por ejemplo, suspensión y rendimiento) para tratar de descubrir errores al azar.
SPIN es una herramienta realmente genial para modelar sus componentes Java (y otros), pero necesita tener un marco útil. Es difícil de usar como está, pero extremadamente poderoso si sabes cómo usarlo. Muchas herramientas usan SPIN debajo del capó.
MultithreadedTC es probablemente la más convencional, pero definitivamente vale la pena ver algunas de las herramientas de análisis estático mencionadas anteriormente.
fuente
La capacidad de espera también puede ser útil para ayudarlo a escribir pruebas unitarias deterministas. Le permite esperar hasta que se actualice algún estado en algún lugar de su sistema. Por ejemplo:
o
También tiene soporte para Scala y Groovy.
fuente
Otra forma de (un poco) probar el código enhebrado, y los sistemas muy complejos en general es a través de Fuzz Testing . No es genial, y no encontrará todo, pero es probable que sea útil y simple de hacer.
Citar:
fuente
He hecho mucho de esto, y sí, apesta.
Algunos consejos:
throwable
campo y verifíquelotearDown
(vea el Listado 1). Si detecta una mala excepción en otro hilo, simplemente asígnelo a arrojable.AtomicBoolean
en tus pruebas. Es seguro para subprocesos, y a menudo necesitará un tipo de referencia final para almacenar valores de clases de devolución de llamada y similares. Ver ejemplo en el Listado 3.@Test(timeout=60*1000)
), ya que las pruebas de concurrencia a veces pueden colgar para siempre cuando se rompen.Listado 1:
Listado 2:
Listado 3:
fuente
Probar la corrección del código MT es, como ya se dijo, un problema bastante difícil. Al final, se reduce a garantizar que no haya carreras de datos sincronizadas incorrectamente en su código. El problema con esto es que hay infinitas posibilidades de ejecución de subprocesos (entrelazados) sobre las cuales no tiene mucho control ( sin embargo, asegúrese de leer este artículo). En escenarios simples, podría ser posible probar la corrección mediante el razonamiento, pero este no suele ser el caso. Especialmente si desea evitar / minimizar la sincronización y no optar por la opción de sincronización más obvia / fácil.
Un enfoque que sigo es escribir un código de prueba altamente concurrente para que las carreras de datos potencialmente no detectadas puedan ocurrir. Y luego ejecuté esas pruebas durante un tiempo :) Una vez me topé con una charla en la que un científico de la computación mostraba una herramienta que hace esto (idear aleatoriamente pruebas a partir de especificaciones y luego ejecutarlas salvajemente, al mismo tiempo, buscando los invariantes definidos Estar destrozado).
Por cierto, creo que este aspecto de probar el código MT no se ha mencionado aquí: identifique invariantes del código que puede verificar al azar. Desafortunadamente, encontrar esos invariantes también es un problema bastante difícil. Además, es posible que no se mantengan todo el tiempo durante la ejecución, por lo que debe encontrar / hacer cumplir los puntos de ejecución donde puede esperar que sean ciertos. Llevar la ejecución del código a tal estado también es un problema difícil (y podría en sí mismo incurrir en problemas de concurrencia. ¡Vaya, es muy difícil!
Algunos enlaces interesantes para leer:
fuente
Pete Goodliffe tiene una serie sobre las pruebas unitarias de código roscado .
Es dificil. Tomo la salida más fácil y trato de mantener el código de subprocesos abstraído de la prueba real. Pete sí menciona que la forma en que lo hago está mal, pero o bien hice la separación correcta o simplemente tuve suerte.
fuente
Para Java, consulte el capítulo 12 de JCIP . Hay algunos ejemplos concretos de escritura de pruebas unitarias deterministas de múltiples subprocesos para al menos probar la corrección e invariantes del código concurrente.
"Probar" la seguridad del hilo con pruebas unitarias es mucho más difícil. Creo que esto es mejor servido por pruebas de integración automatizadas en una variedad de plataformas / configuraciones.
fuente
Me gusta escribir dos o más métodos de prueba para ejecutar en subprocesos paralelos, y cada uno de ellos realiza llamadas al objeto bajo prueba. He estado usando las llamadas Sleep () para coordinar el orden de las llamadas de los diferentes hilos, pero eso no es realmente confiable. También es mucho más lento porque tienes que dormir lo suficiente como para que el tiempo funcione.
Encontré la biblioteca TC Java multiproceso del mismo grupo que escribió FindBugs. Le permite especificar el orden de los eventos sin usar Sleep (), y es confiable. No lo he probado todavía.
La mayor limitación de este enfoque es que solo le permite probar los escenarios que sospecha que causarán problemas. Como han dicho otros, realmente necesita aislar su código multiproceso en un pequeño número de clases simples para tener la esperanza de probarlo a fondo.
Una vez que haya probado cuidadosamente los escenarios que espera causar problemas, una prueba no científica que arroje un montón de solicitudes simultáneas a la clase durante un tiempo es una buena manera de buscar problemas inesperados.
Actualización: he jugado un poco con la biblioteca Java de TC multiproceso, y funciona bien. También porté algunas de sus características a una versión .NET que llamo TickingTest .
fuente
Manejo las pruebas unitarias de componentes roscados de la misma manera que manejo cualquier prueba unitaria, es decir, con inversión de marcos de control y aislamiento. Me desarrollo en el .Net-arena y fuera de la caja el enhebrado (entre otras cosas) es muy difícil (diría que casi imposible) para aislar por completo.
Por lo tanto, he escrito envoltorios que se parecen a esto (simplificado):
A partir de ahí, puedo inyectar fácilmente el IThreadingManager en mis componentes y usar mi marco de aislamiento de elección para que el hilo se comporte como esperaba durante la prueba.
Eso hasta ahora ha funcionado muy bien para mí, y utilizo el mismo enfoque para el grupo de subprocesos, las cosas en System.Environment, Sleep, etc., etc.
fuente
Echa un vistazo a mi respuesta relacionada en
Diseño de una clase de prueba para una barrera personalizada
Está sesgado hacia Java, pero tiene un resumen razonable de las opciones.
En resumen, (IMO) no es el uso de un marco sofisticado que garantizará la corrección, sino cómo se diseña el código multiproceso. Dividir las preocupaciones (concurrencia y funcionalidad) es un gran avance para aumentar la confianza. El software orientado a objetos en crecimiento guiado por pruebas explica algunas opciones mejor que yo.
El análisis estático y los métodos formales (ver Concurrencia: Modelos de estado y programas Java ) es una opción, pero he encontrado que tienen un uso limitado en el desarrollo comercial.
No olvide que las pruebas de estilo de carga / remojo raramente garantizan problemas.
¡Buena suerte!
fuente
tempus-fugit
biblioteca aquí, quehelps write and test concurrent code
;)Recientemente descubrí (para Java) una herramienta llamada Threadsafe. Es una herramienta de análisis estático muy similar a findbugs, pero específicamente para detectar problemas de subprocesos múltiples. No es un reemplazo para las pruebas, pero puedo recomendarlo como parte de la escritura confiable de Java multihilo.
Incluso detecta algunos problemas potenciales muy sutiles en torno a cosas como la subsunción de clase, el acceso a objetos inseguros a través de clases concurrentes y la detección de modificadores volátiles faltantes cuando se utiliza el paradigma de bloqueo de doble verificación.
Si escribes Java multiproceso, pruébalo .
fuente
El siguiente artículo sugiere 2 soluciones. Envolviendo un semáforo (CountDownLatch) y agrega funcionalidades como externalizar datos del hilo interno. Otra forma de lograr este propósito es usar Thread Pool (ver Puntos de interés).
Aspersor: objeto de sincronización avanzada
fuente
Pasé la mayor parte de la semana pasada en una biblioteca universitaria estudiando la depuración de código concurrente. El problema central es que el código concurrente no es determinista. Típicamente, la depuración académica ha caído en uno de los tres campos aquí:
Ahora, como han notado los comentaristas anteriores, puede diseñar su sistema concurrente en un estado más determinista. Sin embargo, si no lo hace correctamente, acaba de volver a diseñar un sistema secuencial nuevamente.
Mi sugerencia sería centrarse en tener un protocolo de diseño muy estricto sobre lo que se enhebra y lo que no se enhebra. Si restringe su interfaz de modo que haya dependencias mínimas entre los elementos, es mucho más fácil.
Buena suerte y sigue trabajando en el problema.
fuente
Tuve la desafortunada tarea de probar código enhebrado y definitivamente son las pruebas más difíciles que he escrito.
Al escribir mis pruebas, utilicé una combinación de delegados y eventos. Básicamente se trata de usar
PropertyNotifyChanged
eventos con unWaitCallback
tipo deConditionalWaiter
encuestas.No estoy seguro de si este fue el mejor enfoque, pero me ha funcionado.
fuente
Asumir bajo el código "multihilo" significaba algo que es
En otras palabras, estamos hablando de probar una clase / método / unidad segura para subprocesos con estado personalizado , que debería ser una bestia muy rara en la actualidad.
Debido a que esta bestia es rara, antes que nada debemos asegurarnos de que haya todas las excusas válidas para escribirla.
Paso 1. Considere modificar el estado en el mismo contexto de sincronización.
Hoy en día, es fácil escribir código simultáneo y asincrónico componible donde IO u otras operaciones lentas se descargan en segundo plano pero el estado compartido se actualiza y consulta en un contexto de sincronización. p. ej., tareas asíncronas / en espera y Rx en .NET, etc. - todas son comprobables por diseño, las tareas y planificadores "reales" se pueden sustituir para hacer que las pruebas sean deterministas (sin embargo, esto está fuera del alcance de la pregunta).
Puede sonar muy limitado, pero este enfoque funciona sorprendentemente bien. Es posible escribir aplicaciones completas en este estilo sin necesidad de hacer ningún estado seguro para subprocesos (lo hago).
Paso 2. Si la manipulación del estado compartido en el contexto de sincronización única no es absolutamente posible.
Asegúrese de que la rueda no se reinventa / definitivamente no hay una alternativa estándar que pueda adaptarse para el trabajo. Debería ser probable que el código sea muy coherente y esté contenido dentro de una unidad, por ejemplo, con una buena probabilidad de que sea un caso especial de alguna estructura de datos estándar segura para subprocesos, como mapa o colección hash o lo que sea.
Nota: si el código es grande / abarca varias clases Y necesita una manipulación de estado de subprocesos múltiples, entonces hay una gran posibilidad de que el diseño no sea bueno, reconsidere el Paso 1
Paso 3. Si se alcanza este paso, entonces debemos probar nuestra propia clase / método / unidad segura para subprocesos con estado personalizado .
Seré sincero: nunca tuve que escribir pruebas adecuadas para ese código. La mayoría de las veces me salgo en el Paso 1, a veces en el Paso 2. La última vez que tuve que escribir código personalizado seguro para subprocesos fue hace tantos años que fue antes de adoptar las pruebas unitarias / probablemente no tendría que escribirlo con el conocimiento actual de todos modos.
Si realmente tuviera que probar dicho código ( finalmente, la respuesta real ), intentaría un par de cosas a continuación
Prueba de esfuerzo no determinista. Por ejemplo, ejecute 100 hilos simultáneamente y verifique que el resultado final sea consistente. Esto es más típico para pruebas de nivel superior / integración de escenarios de usuarios múltiples, pero también se puede usar a nivel de unidad.
Exponga algunos 'ganchos' de prueba donde la prueba puede inyectar algún código para ayudar a crear escenarios deterministas en los que un hilo debe realizar operaciones antes que el otro. Por feo que sea, no se me ocurre nada mejor.
Pruebas demoradas para hacer que los subprocesos se ejecuten y realicen operaciones en un orden particular. Estrictamente hablando, tales pruebas tampoco son deterministas (existe la posibilidad de que el sistema congele / detenga la colección de GC del mundo que puede distorsionar los retrasos orquestados), también es feo pero permite evitar enganches.
fuente
Para el código J2E, he usado SilkPerformer, LoadRunner y JMeter para la prueba de concurrencia de hilos. Todos hacen lo mismo. Básicamente, le brindan una interfaz relativamente simple para administrar su versión del servidor proxy, requerida, con el fin de analizar el flujo de datos TCP / IP, y simular a múltiples usuarios haciendo solicitudes simultáneas a su servidor de aplicaciones. El servidor proxy puede darle la capacidad de hacer cosas como analizar las solicitudes realizadas, presentando la página completa y la URL enviada al servidor, así como la respuesta del servidor, después de procesar la solicitud.
Puede encontrar algunos errores en el modo http inseguro, donde al menos puede analizar los datos del formulario que se envían y modificarlos sistemáticamente para cada usuario. Pero las verdaderas pruebas son cuando se ejecuta en https (Secured Socket Layers). Luego, también tiene que lidiar con la alteración sistemática de la sesión y los datos de cookies, que pueden ser un poco más complicados.
El mejor error que encontré, mientras probaba la concurrencia, fue cuando descubrí que el desarrollador había confiado en la recolección de basura de Java para cerrar la solicitud de conexión que se estableció al iniciar sesión, al servidor LDAP, al iniciar sesión. Esto dio lugar a que los usuarios estuvieran expuestos a las sesiones de otros usuarios y a resultados muy confusos, al intentar analizar lo que sucedió cuando el servidor se puso de rodillas, apenas capaz de completar una transacción, cada pocos segundos.
Al final, usted o alguien probablemente tendrá que abrocharse el cinturón y analizar el código en busca de errores como el que acabo de mencionar. Y una discusión abierta entre departamentos, como la que ocurrió, cuando desarrollamos el problema descrito anteriormente, es muy útil. Pero estas herramientas son la mejor solución para probar código multiproceso. JMeter es de código abierto. SilkPerformer y LoadRunner son propietarios. Si realmente quieres saber si tu aplicación es segura para subprocesos, así es como lo hacen los grandes. He hecho esto para empresas muy grandes profesionalmente, así que no estoy adivinando. Estoy hablando por experiencia personal.
Una advertencia: lleva tiempo entender estas herramientas. No se trata simplemente de instalar el software y activar la GUI, a menos que ya haya tenido alguna exposición a la programación multiproceso. He tratado de identificar las 3 categorías críticas de áreas para comprender (formularios, sesión y datos de cookies), con la esperanza de que al menos comenzar con la comprensión de estos temas lo ayudará a enfocarse en resultados rápidos, en lugar de tener que leer los toda la documentación
fuente
La concurrencia es una interacción compleja entre el modelo de memoria, hardware, cachés y nuestro código. En el caso de Java, al menos tales pruebas han sido abordadas en parte principalmente por jcstress . Se sabe que los creadores de esa biblioteca son autores de muchas características de concurrencia de JVM, GC y Java.
Pero incluso esta biblioteca necesita un buen conocimiento de la especificación del Modelo de Memoria Java para que sepamos exactamente lo que estamos probando. Pero creo que el foco de este esfuerzo son las mircobenchmarks. No grandes aplicaciones comerciales.
fuente
Hay un artículo sobre el tema, que usa Rust como idioma en el código de ejemplo:
https://medium.com/@polyglot_factotum/rust-concurrency-five-easy-pieces-871f1c62906a
En resumen, el truco es escribir su lógica concurrente para que sea robusta para el no determinismo involucrado con múltiples hilos de ejecución, utilizando herramientas como canales y condvas.
Entonces, si así es como ha estructurado sus "componentes", la forma más fácil de probarlos es mediante el uso de canales para enviarles mensajes, y luego bloquear en otros canales para afirmar que el componente envía ciertos mensajes esperados.
El artículo vinculado está completamente escrito usando pruebas unitarias.
fuente
Si está probando un nuevo subproceso simple (ejecutable) .run () Puede burlarse de Thread para ejecutar el ejecutable secuencialmente
Por ejemplo, si el código del objeto probado invoca un nuevo hilo como este
Luego burlarse de nuevos subprocesos y ejecutar el argumento ejecutable secuencialmente puede ayudar
fuente
(si es posible) no use hilos, use actores / objetos activos. Fácil de probar
fuente
Puede usar EasyMock.makeThreadSafe para hacer que la instancia de prueba sea segura
fuente