- Nie testujesz metod (prywatnych lub publicznych) - sprawdzasz zachowanie swojej klasy.A jeśli nie sprawdziłeś jakiegoś zachowania, nie możesz powiedzieć, że zostało zaimplementowane. Istnieje kilka sposobów na wywołanie tego zachowania - publiczny interfejs twojej klasy lub pewne zdarzenie zależne. Nie jest również konieczne, aby wywoływanie zachowań zmieniało coś, co osiągnął interfejs publiczny, ale interakcje z zależnościami również mają znaczenie.
- Zobacz przykład poniżej - pokazuje, jak przetestować takie "ukryte" zachowanie.
- Zobacz przykład poniżej - pokazuje, jak podzielić obowiązki, wstrzyknąć zależności i wyśmiać je.
W rzeczywistości twoja klasa ma zbyt wiele obowiązków - jedna planuje jakieś zadanie, a druga - wykonuje pewne akcje. Spróbuj podzielić klasę na dwie osobne klasy za pomocą single responsibilities.
Więc, planowanie harmonogramów idzie :) API planującego może być tak:
public interface IScheduler
{
event EventHandler<SchedulerEventArgs> Alarm;
void Start();
void Stop();
}
Zapomnij o scheduler teraz. Wróć i zaimplementuj swoją drugą klasę, która wyświetli kilka ostrzeżeń. Chodźmy testową (z Min): realizacja
[Test]
public void ShouldStopDisplayingWarningsWhenTimeIsOut()
{
Mock<IDisplay> display = new Mock<IDisplay>();
Mock<IScheduler> scheduler = new Mock<IScheduler>();
Foo foo = new Foo("Bar", scheduler.Object, display.Object);
scheduler.Raise(s => s.Alarm += null, new SchedulerEventArgs(0));
display.Verify(d => d.Execute("Bar", WarningState.Ending, null));
scheduler.Verify(s => s.Stop());
}
Zapis:
public class Foo
{
private readonly IScheduler _scheduler;
private readonly IDisplay _display;
private readonly string _name;
public Foo(string name, IScheduler scheduler, IDisplay display)
{
_name = name;
_display = display;
_scheduler = scheduler;
_scheduler.Alarm += Scheduler_Alarm;
_scheduler.Start();
}
private void Scheduler_Alarm(object sender, SchedulerEventArgs e)
{
_display.Execute(_name, WarningState.Ending, null);
_scheduler.Stop();
}
}
przechodzi test. Napisz następną:
[Test]
public void ShouldNotStopDisplayingWarningsWhenTimeRemains()
{
Mock<IDisplay> display = new Mock<IDisplay>(MockBehavior.Strict);
Mock<IScheduler> scheduler = new Mock<IScheduler>(MockBehavior.Strict);
scheduler.Setup(s => s.Start());
Foo foo = new Foo("Bar", scheduler.Object, display.Object);
scheduler.Raise(s => s.Alarm += null, new SchedulerEventArgs(1));
}
Test nie powiódł się. Ach, trzeba warunku pozostały czas:
private void Scheduler_Alarm(object sender, SchedulerEventArgs e)
{
if (e.RemainingTime > 0)
return;
_display.Execute(_name, WarningState.Ending, null);
_scheduler.Stop();
}
Można kontynuować pisanie testów dla klasy, która odpowiada za rozpatrzenie powiadomienia scheduler i wykonywanie niektórych ostrzeżenia na wyświetlaczu. Po zakończeniu możesz napisać implementację dla swojego interfejsu IScheduler
. Nie ma znaczenia, w jaki sposób zaimplementujesz planowanie - za pośrednictwem System.Windows.Forms.Timer lub poprzez System.ThreadingTimer lub w inny sposób.
Jakie zachowanie chcesz zweryfikować? –
Czy sama właściwa metoda ma jakąkolwiek zależność od czasu? Twój test jednostkowy powinien przetestować funkcjonalność metody; fakt, że jest wywoływany regularnie, nie powinien zmieniać faktu, że chcesz sprawdzić, czy metoda działa. Powiedziałbym, że zdecydowanie nie ma potrzeby kpić z timera, chyba że sukces metody zależy od czasu. Dostępność metody nie powinna mieć znaczenia, jeśli chodzi o testowanie; to funkcjonalna część twojego programu. – dash
+1, ponieważ pisałem dokładnie to samo pytanie w przypadku testowania pól prywatnych, pobiłeś mnie na czas – HatSoft