单元测试不立即执行的代码

时间:2009-03-10 02:48:41

标签: c# unit-testing c#-3.0 nunit xna

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

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

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

是否可以单独测试不立即执行的代码?

干杯,

7 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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
    }
}

答案 2 :(得分:2)

作为旁注。我们通常会尝试使用NUnit category标记慢速运行测试,并可以选择在某些版本上跳过这些测试。

答案 3 :(得分:1)

是的,在你的例子中这样做是行不通的。

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

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

BTW,这种方法通常被称为mocking;在这种情况下,测试类将是模拟对象。

答案 4 :(得分:1)

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

  1. 注册定时委托执行时,会设置适当的时间。这可能需要使用超时和代表数量的各种组合进行测试。
  2. 代表以适当的方式执行。
  3. 以这种方式分离测试将允许您测试您的计时机制是否按预期工作,并且有少量短暂超时(测试您需要考虑的所有情况)。请记住,根据系统上的当前负载以及组件代码的复杂程度(在IntervalManager中)执行给定委托所需的实际时间可能需要一点余地。

答案 5 :(得分:0)

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

答案 6 :(得分: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]运行代码。