gpt4 book ai didi

c# - 对使用 Timer 的类进行单元测试

转载 作者:IT王子 更新时间:2023-10-29 04:04:46 28 4
gpt4 key购买 nike

我有一个类,它有一个类型为 System.Windows.Forms.Timer 的私有(private)成员。还有一个私有(private)方法,每次我的计时器计时时都会调用它。

  1. 是否值得测试该方法? (因为它是私有(private)的)
  2. 我如何测试它? (我知道我可以让我的测试类继承我想测试的类...)
  3. 我应该 mock 我的计时器吗?因为如果我必须测试一个使用内部计时器的类,我的测试可能需要很长时间才能完成,对吗?

编辑:

实际上,该方法对时间有依赖性,代码如下:

private void alertTick(object sender, EventArgs e) {
if (getRemainingTime().Seconds <= 0) {
Display.execute(Name, WarningState.Ending, null);
AlertTimer.Stop();
}
else {
var warning = _warnings.First(x => x == getRemainingTime());

if (warning.TotalSeconds > 0)
Display.execute(Name, WarningState.Running, warning);
}
}

如您所见,如果计时器正在运行,它会在结束时(剩余时间为 0 时)使用不同的参数调用 Display.execute()。会不会是设计问题?

最佳答案

  1. 您不是在测试方法(私有(private)或公共(public))——您是在验证类的行为。如果您还没有验证某些行为,那么您就无法判断它是否已实现。可以通过多种方式调用此行为 - 您的类的公共(public)接口(interface),或依赖的某些事件。行为调用也不一定会改变公共(public)接口(interface)所达到的某些内容,与依赖项的交互也很重要。
  2. 请参阅下面的示例 - 它显示了如何测试此类“隐藏”行为。
  3. 请参阅下面的示例 - 它展示了如何拆分职责、注入(inject)依赖项并模拟它们。

实际上你的类(class)有太多的职责 - 一个是安排一些任务,另一个 - 执行一些 Action 。尝试使用 single responsibilities 将您的类(class)分成两个单独的类(class).

因此,调度转到调度器 :) 调度器的 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 接口(interface)编写实现。您将如何实现调度并不重要——通过 System.Windows.Forms.Timer 或通过 System.ThreadingTimer,或其他一些方式。

关于c# - 对使用 Timer 的类进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11495830/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com