Aquí está mi enfoque. Esta prueba no se ocupa de los bloqueos, se trata de consistencia. Estoy probando un método con un bloque sincronizado, con el código que se ve algo como esto:
synchronized(this) {
int size = myList.size();
// do something that needs "size" to be correct,
// but which will change the size at the end.
...
}
Es difícil producir un escenario que va a producir de manera fiable un conflicto hilo, pero aquí es lo que hice.
Primero, mi prueba de unidad creó 50 hilos, los lancé todos al mismo tiempo, y los hice llamar a todos por mi método. Yo uso una cuenta atrás Latch para empezar a todos al mismo tiempo:
CountDownLatch latch = new CountDownLatch(1);
for (int i=0; i<50; ++i) {
Runnable runner = new Runnable() {
latch.await(); // actually, surround this with try/catch InterruptedException
testMethod();
}
new Thread(runner, "Test Thread " +ii).start(); // I always name my threads.
}
// all threads are now waiting on the latch.
latch.countDown(); // release the latch
// all threads are now running the test method at the same time.
Esto puede o no puede producir un conflicto. My testMethod() debería ser capaz de lanzar una excepción si ocurre un conflicto. Pero aún no podemos estar seguros de que esto genere un conflicto. Entonces no sabemos si la prueba es válida. Así que este es el truco: Comente sus palabras clave sincronizadas y ejecute la prueba. Si esto produce un conflicto, la prueba fallará. Si falla sin la palabra clave sincronizada, su prueba es válida.
Eso es lo que hice, y mi prueba no falló, por lo que no era (todavía) una prueba válida. Pero pude producir una falla confiable al colocar el código anterior dentro de un bucle y ejecutarlo 100 veces consecutivas. Así que llamo al método 5000 veces. (Sí, esto producirá una prueba lenta. No se preocupe. Sus clientes no se molestarán con esto, por lo que tampoco debería hacerlo).
Una vez que coloque este código dentro de un bucle externo, fue capaz de ver con fiabilidad una falla en la vigésima iteración del bucle externo.Ahora estaba seguro de que la prueba era válida y restauré las palabras clave sincronizadas para ejecutar la prueba real. (Funcionó.)
Puede descubrir que la prueba es válida en una máquina y no en otra. Si la prueba es válida en una máquina y sus métodos pasan la prueba, entonces es presumiblemente seguro para subprocesos en todas las máquinas. Pero debe probar la validez de la máquina que ejecuta las pruebas de su unidad nocturna.
He realizado pruebas unitarias de la manera descrita anteriormente, pero siempre sentí que hay un elemento de aleatoriedad en el resultado, por lo que seguiré las respuestas aquí con interés: o) –
Duplicado: http: // stackoverflow.com/questions/1715822/unit-test-for-thread-safe-ness – JeffH
@JeffH Sí, tienes razón. Pffffff, deja de tratar de ser un policía SO. –