Sto riscontrando un problema con un'unità che testa una classe che genera eventi all'avvio e al termine di un thread. Una versione ridotta della sorgente incriminata è la seguente:Unità di test di un evento da un thread
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();
}
}
Ho poi ho un test per verificare che i Finished
generato l'evento dopo il LongRunningMethod
ha terminato come segue:
[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);
}
}
}
Quindi l'idea qui poiché il test si bloccherà per un massimo di un secondo o fino a quando l'evento Finish
non viene attivato, prima di verificare se è impostato il flag finished
.
Chiaramente ho fatto qualcosa di sbagliato a volte il test passerà, a volte no. Il debug sembra molto difficile così come i breakpoint che mi aspetto di essere colpiti (il metodo OnFinished
, ad esempio) non sempre sembrano essere.
Sto assumendo che questo sia solo il mio fraintendimento del modo in cui funziona il threading, quindi spero che qualcuno possa illuminarmi.
Grazie per tutte le risposte. Ho anche introdotto un altro problema avendo il metodo lavoratore filo (cioè LongRunningMethod) impostare il proprio flag di controllo all'avvio. Oggi è stato certamente un corso accelerato su come introdurre le condizioni di gara nel tuo codice, doh! – Dougc