Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 单元测试使用计时器的类_C#_Unit Testing_Tdd - Fatal编程技术网

C# 单元测试使用计时器的类

C# 单元测试使用计时器的类,c#,unit-testing,tdd,C#,Unit Testing,Tdd,我有一个类,它有一个私有成员,类型为System.Windows.Forms.Timer。还有一个私有方法,每次我的计时器滴答作响时都会调用它 这种方法值得测试吗?因为它是私人的 我如何测试它?我知道我可以让我的测试类继承我想要测试的类。。。 我应该嘲笑我的计时器吗?因为如果我必须测试一个使用内部计时器的类,我的测试可能需要很多时间才能完成,对吗? 编辑: 实际上,该方法依赖于时间,下面是代码: private void alertTick(object sender, EventArgs e)

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

这种方法值得测试吗?因为它是私人的 我如何测试它?我知道我可以让我的测试类继承我想要测试的类。。。 我应该嘲笑我的计时器吗?因为如果我必须测试一个使用内部计时器的类,我的测试可能需要很多时间才能完成,对吗? 编辑:

实际上,该方法依赖于时间,下面是代码:

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);
    }
}
如您所见,如果计时器正在运行,它将调用Display.execute,参数与剩余时间等于0时不同。这是设计的问题吗

这种方法值得测试吗?因为它是私人的

您的目的是决定代码是否有效。即使它是一个私有方法,它也应该生成一个公共接口可以访问的输出。您应该以用户能够知道类是否工作的方式来设计类

此外,在进行单元测试时,如果可以模拟计时器,则可以访问分配给计时器的已用事件的回调

我如何测试它?我知道我可以让我的测试类继承 我想测试的类

您可以在这里使用适配器类。首先,您必须定义一个抽象,因为Timer类不提供抽象

public interface ITimer
{
    void Start();
    void Stop();
    double Interval { get; set; }
    event ElapsedEventHandler Elapsed;
    //and other members you need
}
然后可以在适配器类中实现该接口,只需从Timer类继承即可

public class TimerAdaper : Timer, ITimer { }
您应该将抽象作为属性注入构造函数中,以便在测试中模拟它

public class MyClass
{
    private readonly ITimer _timer;

    public MyClass(ITimer timer)
    {
        _timer = timer
    }
}
我应该嘲笑我的计时器吗?因为如果我要测试一个类 使用内部计时器,我的测试可能需要很多时间才能完成, 对吧?

当然,你应该嘲笑你的计时器。单元测试不能依赖于系统时间。您应该通过模拟来引发事件,并查看代码的行为

您不是在测试私有或公共方法,而是在验证类的行为。如果您还没有验证某些行为,则无法判断它是否已实现。有几种方法可以调用此行为—类的公共接口或依赖项中的某些事件。行为调用也不一定会改变公共接口所达到的效果,与依赖项的交互也很重要。 请参见下面的示例-它显示了如何测试此类隐藏行为。 请参见下面的示例-它展示了如何划分职责、注入依赖项和模拟它们。 实际上,您的类有太多的职责——一个是安排一些任务,另一个是执行一些操作。试着把你的班级分成两个独立的班级

因此,调度将转到调度程序:调度程序的API可能类似于:

public interface IScheduler
{
    event EventHandler<SchedulerEventArgs> Alarm;
    void Start();
    void 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));
}

您可以继续为类编写测试,该类负责处理调度程序警报并在显示时执行一些警告。完成后,可以为isScheduler接口编写实现。无论您将如何实现调度—通过System.Windows.Forms.Timer或通过System.ThreadingTimer或其他方式。

您想验证什么行为?实际方法本身是否依赖于时间?单元测试应该测试方法的功能;定期调用该方法的事实不应改变您想要测试该方法是否有效的事实。我想说,除非方法的成功取决于时间,否则绝对没有必要模仿计时器。当涉及到测试时,方法的可访问性并不重要;这是你程序的一个功能部分。+1因为我在私人领域测试中输入了完全相同的问题,所以你在时间上击败了我。可能重复的值得测试的问题是你可以更好地处理的。这有风险吗?它会失败吗?一般的准则是通过使用私有方法的公共方法来测试私有方法。最后,如果时间方面/角色使测试变得困难/不可预测,那么您应该模拟它。请您详细说明私人是否值得测试,然后如何测试them@HatSoft如果一个类的公共接口不能访问一段公共或私有逻辑,那么代码就不能使用。因此,我们应该始终能够测试类中的所有代码。@HatSoft即使附加到计时器已用事件的代码是私有的,它的启动部分也应该在某些公共成员构造函数中。这样就可以访问私有部分。如果没有上下文,我不能说你如何测试它,但你应该也可以测试它。@dtryon&Ufuk谢谢你,你能分享一些关于如何测试private的链接吗s@HatSoft这不是直接测试private的逻辑。它是关于找到执行privates功能的公共流,然后制作一个使用该流的测试。我们如何为调度器实现编写单元测试@偷简单积分 毫无疑问:
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();
}