C# 不使用';我不能立即执行

C# 不使用';我不能立即执行,c#,unit-testing,c#-3.0,nunit,xna,C#,Unit Testing,C# 3.0,Nunit,Xna,我正在使用C#3.0和NUnit。我想知道是否有一种标准方法可以对经过一段时间后执行的代码执行单元测试。例如,我有一个简单的静态类,我可以用它注册方法,并在n毫秒后调用它们。我需要确保委托方法中的代码正在被调用 例如,以下测试将始终通过,因为在方法退出之前没有断言 [Test] public void SampleTest() { IntervalManager.SetTimeout(delegate{ Assert.Equals(now.Millisecond + 1

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

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

[Test]
public void SampleTest()
{
    IntervalManager.SetTimeout(delegate{ 
        Assert.Equals(now.Millisecond + 100, DateTime.Now.Millisecond); 
    }, 100);
}
甚至可以对不立即执行的代码进行单元测试吗

干杯


保罗:当然你可以测试一下。您只需等待它执行。

是的,像您的示例中那样执行是行不通的

相反,我建议您创建一个测试类,用作委托,记录调用其方法的时间和时间

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


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

那么您到底在测试什么呢?你在测试计时器的工作情况吗?或者您的代码正确地设置了计时器,以便计时器在到期时执行回调?在不知道代码是什么样子的情况下,我假设您真正想要测试的是后者。我的答案是:(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
    }
}

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

也许我遗漏了一些东西,但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]运行代码。

正如其他几个答案所指出的,长时间运行测试通常是个坏主意。为了便于测试这个组件,你应该考虑到你确实有两个不同的东西要测试。
  • 注册定时委托执行时,将设置正确的时间。这可能需要通过各种超时和代表人数组合进行测试
  • 以正确的方式执行委托

  • 以这种方式分离测试将允许您在少量短超时的情况下测试您的计时机制是否按预期工作(测试您需要考虑的所有情况)。请记住,根据系统上的当前负载和组件代码的复杂程度(即
    IntervalManager
    ),执行给定委托所需的实际时间可能需要一点回旋余地。

    如何等待几秒钟并验证测试类的状态?使用老式的sleep()黑客?好吧,只需使用标准库中的sleep()或等效函数(不知道C#中的名称)。那为什么会是黑客呢?你只是在等待方法被记录下来所需要的时间。单元测试应该很快。在测试中引入定时等待会降低速度——如果您有任何数量可观的此类测试,那么每次测试1/2秒的速度就太慢了。我建议使用mock重构到一个解决方案是一个更好的方法来处理这个问题。我同意,半秒是一个任意的时间,应该最小化。在单元测试期间等待另一个线程完成工作的原则仍然有效,无论该线程是否在计时器上。但我同意,单元测试期间的定时等待会减慢速度,应该避免。