2012-01-25 50 views
2

我们正在开发一个使用TDD的WPF应用程序。由于我们已经在这个解决方案上工作了将近两年,我们已经写了大量的测试(现在几乎有2000个Unittests)。如何优化验证异步代码的测试?

有一些类需要实现多线程和异步功能。例如可以发送和接收消息并解析它们的通信组件。依赖关系总是使用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毫秒。我们优化了测试,使用活动轮询方法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(); 
} 

现在我们可以使用这个WaitFor.True(...)通过改变AssertWasCalled的方法:

var fooTriggered = false; 
myStub.Stub(x => x.Bar("Foo")).Do((Action)(() => fooTriggered = true))); 

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

此结构将终止早,如果条件满足,但无论如何 - 这对我们来说需要很长时间。运行我们所有的2000年测试需要大约5分钟(构建和运行它们)。

有没有什么聪明的技巧我们可以如何优化代码?

回答

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.Wait被调用。然后回调可以进入并监控Monitor。然后测试会“醒来”,一旦回调退出监视器,控制权就会恢复并退出,从而允许您断言。

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

如果您使用它,您可以创建一个为您执行复杂监控位的类。 This is one I wrote来处理UI自动化中的异步检查;适应它为你正在做什么可能会帮助你。

+0

非常感谢,我喜欢这种测试方式!将尝试这一个。 – Guffel

+0

哦,看,我没有Monitor.Wait(waitingRoom,) - 所以不需要做怪异的定时器gubbins。尼斯。 – Lunivore