如何优化验证异步代码的测试?

时间:2012-01-25 09:15:54

标签: multithreading unit-testing asynchronous tdd

我们正在使用TDD开发WPF应用程序。由于我们已经在这个解决方案上工作了近两年,我们已经编写了大量的测试(现在几乎有2000个单元测试)。

有些类需要实现多线程和异步功能。例如,可以发送和接收消息并解析消息的通信组件。始终使用RhinoMocks模拟依赖项。

我们针对这些类的测试方法看起来非常相似,如下所示:

[TestMethod]
public void Method_Description_ExpectedResult(){
  // Arrange
  var myStub = MockRepository.GenerateStub<IMyStub>();
  var target = new MyAsynchronousClass(myStub);

  // Act
  var target.Send("Foo");
  Thread.Sleep(200);

  //Assert
  myStub.AssertWasCalled(x => x.Bar("Foo"));
}

如您所见,由于Thread.Sleep(),此测试至少运行200 ms。我们使用主动轮询方法(s.th.)优化了替换AssertWasCalled的测试。像这样:

public static bool True(Func<bool> condition, int times, int waitTime)
{
    for (var i = 0; i < times; i++)
    {
        if (condition())
            return true;
        Thread.Sleep(waitTime);
    }

    return condition();
}

我们现在可以通过将AssertWasCalled更改为:

来使用此WaitFor.True(...)方法
var fooTriggered = false;
myStub.Stub(x => x.Bar("Foo")).Do((Action)(() => fooTriggered = true)));

WaitFor.True(() => fooTriggered, 20, 20);
Assert.IsTrue(fooTriggered);

如果条件匹配,此构造将提前终止,但无论如何 - 这对我们来说需要太长时间。运行我们所有的2000次测试需要大约5分钟(构建和运行它们)。

我们如何才能优化这样的代码?

1 个答案:

答案 0 :(得分:2)

您可以使用显示器。我正在做这个,所以请原谅我,如果它没有完全编译,但它看起来像:

[TestMethod]
public void Method_Description_ExpectedResult(){
  // Arrange
  var waitingRoom = new object();
  var myStub = MockRepository.GenerateStub<IMyStub>();
  myStub.Setup(x => x.Bar("Foo")).Callback(x => 
      {
          Monitor.Enter(waitingRoom);
          Monitor.Pulse(waitingRoom);
          Monitor.Exit(waitingRoom);
      }

  var target = new MyAsynchronousClass(myStub);

  // Act

  Monitor.Enter(waitingRoom);
  target.Send("Foo");
  Monitor.Wait(waitingRoom);
  Monitor.Exit(waitingRoom);

  //Assert
  myStub.AssertWasCalled(x => x.Bar("Foo"));
}

在Monitor中编写的代码无法运行,直到它是免费的。测试将导致代理线程一直等到Monitor.Wait被调用。然后回调可以进入并脉冲监视器。然后测试“唤醒”,一旦回调退出监视器,它就会得到控制并退出,允许你断言。

我唯一没有涉及的是,如果Bar(“Foo”)没有被调用它会挂起,所以你可能也希望有一个定时器脉冲线程。

如果您经常使用它,您可以创建一个为您执行复杂监视位的类。 This is one I wrote处理UI自动化中的异步检查;根据你的工作进行调整可能会对你有所帮助。