- 您不是在测试方法(私有或公共) - 您正在验证班级的行为。而且,如果您还没有验证某些行为,那么您就无法判断它是否已实施。可以通过多种方式调用此行为 - 类的公共接口,或某些依赖事件。行为调用也不一定会改变公共接口所达到的内容,与依赖项的交互也很重要。
- 请参见下面的示例 - 它显示了如何测试这种“隐藏”行为。
- 请参见下面的示例 - 它展示了如何拆分职责、注入依赖项和模拟它们。
实际上你的班级有太多的责任 - 一个是安排一些任务,另一个 - 执行一些动作。尝试将您的班级分成两个具有单一职责的单独班级。
因此,调度转到调度程序 :) 调度程序的 API 可能类似于:
public interface IScheduler
{
event EventHandler<SchedulerEventArgs> Alarm;
void Start();
void Stop();
}
现在忘记调度程序。返回并实现你的第二个类,这将显示一些警告。让我们先测试一下(使用起订量):
[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 或其他方式。