Testy jednostkowe: testowanie zdarzeń

Ostatni natknąłem się na problem testowania zdarzeń. Sprawa niestety nie jest prosta na pierwszy rzut oka. Zdarzenia w aplikacji wywołują się asynchronicznie (nie wiemy dokładnie kiedy zdarzenie zajdzie) więc aby je przetestować musimy poczekać aż dane zdarzenie wystąpi i wtedy zweryfikować poprawność danych. Tak więc nasuwa się pytanie jak wstrzymać metodę testową aby czekała do momentu zajścia zdarzenia lub jeśli jest to wymagane zasygnalizowała nam, że czas na wykonanie zadania minął.

Bardzo przydatna w takich przypadkach okazuje się klasa Monitor i instrukcja lock. Cały mechanizm opiera się na zablokowaniu obiektu w metodzie testującej za pomocą metody Monitor.Wait i czekanie na odblokowanie go przez zdarzenie metoda Monitor.Pulse. Taka funkcjonalność w zupełności wystarcza na potrzeby testów jednostkowy, a prostota sprawia, że testy tworzymy w szybki sposób. Przyjdźmy do przykładu i zobaczmy jak to wszystko wygląda w praktyce.

[csharp]

[TestMethod()]
public void MyExampleEventTest()
{
MyApplication target = new MyApplication();
bool result = false;
target.TestEvent += (s, e) =>
{
//Do something
result = s is MyApplication
lock (this)
{
Monitor.Pulse(this);
}
};
int timeout = 1000;
lock (this)
{
if (!Monitor.Wait(this,timeout)) //Wait for Event
Assert.Fail("Time out");

}
Assert.IsTrue(result);

}
[/csharp]

W przedstawionym przykładzie wykorzystałem funkcję Wait która po określonym czasie kończy działanie. Oczywiście możemy użyć też innej wersji funkcji Wait np. bez podawania czasu, dzięki czemu metoda testujące będzie czekać do skutku czyli do momentu wystąpienia zdarzenia.