Ответ 1
- Вы не тестируете методы (частные или общедоступные) - вы проверяете поведение своего класса. И если вы не проверили какое-либо поведение, то вы не можете сказать, что оно было реализовано. Существует несколько способов вызвать это поведение - открытый интерфейс вашего класса или какое-либо событие в зависимости. Также не обязательно, чтобы поведение вызова изменило значение, достигнутое публичным интерфейсом, также имеет значение взаимодействие с зависимостями.
- См. пример ниже - он показывает, как тестировать такое "скрытое" поведение.
- См. пример ниже - он показывает, как разделить обязанности, ввести зависимости и высмеять их.
На самом деле у вашего класса слишком много обязанностей - один из них планирует какую-то задачу, а другой - выполнение некоторых действий. Попробуйте разделить свой класс на два отдельных класса с отдельные обязанности.
Итак, планирование идет в планировщик:) API планировщика может быть следующим:
public interface IScheduler
{
event EventHandler<SchedulerEventArgs> Alarm;
void Start();
void Stop();
}
Забудьте о планировщике сейчас. Верните и реализуйте свой второй класс, который отобразит некоторые предупреждения. Сначала отпустите тест (с помощью Moq):
[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());
}
Запись реализации:
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();
}
}
Тест проходит. Напишите еще один:
[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));
}
Тест завершился неудачно. Ах, вам нужно условие для оставшегося времени:
private void Scheduler_Alarm(object sender, SchedulerEventArgs e)
{
if (e.RemainingTime > 0)
return;
_display.Execute(_name, WarningState.Ending, null);
_scheduler.Stop();
}
Вы можете продолжать писать тесты для своего класса, которые отвечают за обработку предупреждений планировщика и выполнение некоторых предупреждений на дисплее. Когда вы закончите, вы можете написать реализацию для вашего интерфейса IScheduler
. Неважно, как вы будете выполнять планирование - через System.Windows.Forms.Timer или через System.ThreadingTimer или каким-либо другим способом.