Estoy teniendo problemas para probar una clase que dispara eventos cuando un hilo se inicia y termina. Una versión reducida de la fuente infractor es el siguiente:Unidad Comprobación de un evento de un hilo
public class ThreadRunner
{
private bool keepRunning;
public event EventHandler Started;
public event EventHandler Finished;
public void StartThreadTest()
{
this.keepRunning = true;
var thread = new Thread(new ThreadStart(this.LongRunningMethod));
thread.Start();
}
public void FinishThreadTest()
{
this.keepRunning = false;
}
protected void OnStarted()
{
if (this.Started != null)
this.Started(this, new EventArgs());
}
protected void OnFinished()
{
if (this.Finished != null)
this.Finished(this, new EventArgs());
}
private void LongRunningMethod()
{
this.OnStarted();
while (this.keepRunning)
Thread.Sleep(100);
this.OnFinished();
}
}
entonces tengo una prueba para comprobar que los Finished
desencadena el evento después de la LongRunningMethod
ha terminado de la siguiente manera:
[TestClass]
public class ThreadRunnerTests
{
[TestMethod]
public void CheckFinishedEventFiresTest()
{
var threadTest = new ThreadRunner();
bool finished = false;
object locker = new object();
threadTest.Finished += delegate(object sender, EventArgs e)
{
lock (locker)
{
finished = true;
Monitor.Pulse(locker);
}
};
threadTest.StartThreadTest();
threadTest.FinishThreadTest();
lock (locker)
{
Monitor.Wait(locker, 1000);
Assert.IsTrue(finished);
}
}
}
Así que la idea aquí ya que la prueba se bloqueará durante un máximo de un segundo, o hasta que se active el evento Finish
, antes de verificar si se ha establecido el indicador finished
.
Es evidente que he hecho algo mal, ya que a veces la prueba pasará, a veces no lo hará. La depuración parece muy difícil, así como los puntos de ruptura que esperaría que me tocara (el método OnFinished
, por ejemplo) no siempre parece ser así.
Supongo que esta es solo mi incomprensión de la forma en que funciona el enhebrado, así que espero que alguien pueda iluminarme.
Gracias por todas las respuestas. También introduje otro error al hacer que el método thread worker (es decir, LongRunningMethod) establezca su propio indicador de control cuando se inicia. Hoy ciertamente ha sido un curso intensivo sobre cómo introducir condiciones de carrera en tu código, ¡do! – Dougc