2

我正在使用 C# 3.0 和 NUnit。我想知道是否有一种标准方法可以对在一段时间后执行的代码执行单元测试。例如,我有一个简单的静态类,我可以向它注册方法,并在 n 毫秒后调用它们。我需要确保正在调用委托方法中的代码。

例如,以下测试将始终通过,因为在方法退出之前没有任何断言。

[Test]
public void SampleTest()
{
    IntervalManager.SetTimeout(delegate{ 
        Assert.Equals(now.Millisecond + 100, DateTime.Now.Millisecond); 
    }, 100);
}

甚至可以对不立即执行的代码进行单元测试吗?

干杯,

保罗

4

7 回答 7

2

那么你到底在测试什么?你在测试定时器的工作吗?或者您的代码正确设置了一个计时器,以便在到期时计时器执行回调?在不知道代码是什么样子的情况下,我假设您真正想要测试的是后者。我的回答是(1)这对于静态方法可能会很困难,(2)你可能需要使用依赖注入并注入模拟计时器等,它们实际上并不运行生成的方法,而是记录通过期望您的代码进行了正确的调用。

于 2009-03-10T03:05:23.410 回答
2

这个怎么样?它会导致测试阻塞一些预期的最大时间,以便回调触发并在保释之前完成,并报告错误。

public void Foo() {
    AutoResetEvent evt = new AutoResetEvent(false);
    Timer t = new Timer(state => {
        // Do work
        evt.Set();
    }, null, 100, Timeout.Infinite);
    if (evt.WaitOne(500)) {
        // method called and completed
    } else {
        // timed out waiting
    }
}
于 2009-03-10T03:48:45.660 回答
2

作为旁注。我们通常会尝试使用NUnit 类别标记运行缓慢的测试,并且可以选择在某些构建上跳过这些测试。

于 2009-05-07T06:54:07.210 回答
1

是的,像你的例子那样做是行不通的。

相反,我建议您创建一个测试类,用作委托,记录何时调用其方法以及何时调用。

然后,您将您的模拟注入您要测试的 IntervalManager。然后您的测试方法必须等待 IntervalManager(使用 IntervalManager 提供的合适方法,或者等待几秒钟),然后您可以验证测试类的状态。

顺便说一句,这种方法通常被称为 模拟;在这种情况下,测试类将是模拟对象。

于 2009-03-10T03:02:28.517 回答
1

正如其他几个答案所表明的那样,长时间运行的测试通常是一个坏主意。为了便于测试这个组件,您应该考虑到您确实有两个不同的东西要测试。

  1. 当您注册定时委托执行时,会设置正确的时间。这可能需要使用超时和代表数量的各种组合进行测试。
  2. 委托以适当的方式执行。

以这种方式分离测试将允许您测试您的计时机制是否按预期工作,只需少量短超时(测试您需要考虑的所有情况)。请记住,根据系统上的当前负载以及组件代码的复杂程度(即IntervalManager.

于 2009-11-06T21:45:38.260 回答
0

当然你可以测试一下。你只需要等待它执行。

于 2009-03-10T02:51:32.460 回答
0

也许我遗漏了一些东西,但 Visual Studio 的单元测试具有特殊属性,您可以将其放在控制执行顺序和其他内容的方法上。这应该在您第一次制作单元测试项目时自动生成:

    #region Additional test attributes
    // 
    //You can use the following additional attributes as you write your tests:
    //
    //Use ClassInitialize to run code before running the first test in the class
    //[ClassInitialize]
    //public static void MyClassInitialize(TestContext testContext) {
    //}
    //
    //Use ClassCleanup to run code after all tests in a class have run
    //[ClassCleanup()]
    //public static void MyClassCleanup()
    //{
    //}
    //
    //Use TestInitialize to run code before running each test
    //[TestInitialize()]
    //public void MyTestInitialize()
    //{
    //}
    //
    //Use TestCleanup to run code after each test has run
    //[TestCleanup()]
    //public void MyTestCleanup()
    //{
    //}
    //
    #endregion

因此,使用 [ClassInitialize] 应该允许您将必须首先执行的任何内容写入方法中。然后你的测试就可以运行了。或者您可以使用 [TestInitialize] 在每次测试之前运行代码。

于 2009-11-06T21:33:05.743 回答