如何在单元测试中处理后台线程中的异常?

时间:2009-09-28 19:09:56

标签: c# multithreading unit-testing visual-studio-2008

我正在编写一个单元测试套件来测试TCP / IP通信库。

当我使用BeginAcceptClient和EndAcceptClient时,消息将在后台线程中接收。

收到消息后,我对它执行一些断言,但如果任何断言失败,则VSTestHost.exe崩溃。

我用Google搜索了一下,发现Assert异常是在后台线程中引发的。

编辑:我正在做的示例代码,只是为了说明:


public void TestFooMessage() {
    Server.OnReceive += (s, e) => {
        Assert.IsInstanceOfType(e.Message, typeof(Foo));
    };

    var message = new Foo();
    Client.Send(message);
}

有没有人知道如何让它按预期工作:记录断言并继续正常运行?

3 个答案:

答案 0 :(得分:6)

您不应该在后台线程中编写Asserts(例如:后台事件处理程序),因为测试框架无法处理此问题。你应该只在那里收集价值。例如,您可以使用AutoResetEvents同步主线程。将值写入字段,断言主线程中的字段。

如果邮件永远不会进入,则需要暂停。

有点伪代码(实际上不是伪代码):

private AutoResetEvent ReceiveEvent = new AutoResetEvent(false);
private EventArgs args;
private bool ReceiveCalled = false;

// event handler with some argument
private void Receive(object sender, EventArgs args)
{
  // get some arguments from the system under test
  this.args= args;

  // set the boolean that the message came in
  ReceiveCalled = true;

  // let the main thread proceed
  ReceiveEvent.Set();
}

[TestMethod]
public void Test()
{
  // register handler
  Server.OnReceive += Receive;

  var message = new Foo();
  Client.Send(message);

  // wait one second for the messages to come in
  ReceiveEvent.WaitOne(1000);

  // check if the message has been received
  Assert.IsTrue(
    ReceiveCalled, 
    "AcceptClientReceived has not been called");

  // assert values from the message
  Assert.IsInstanceOfType(args.Message, typeof(Foo))    
}

顺便说一句:您仍然可以将处理程序编写为lambda表达式,甚至可以通过使用局部变量来避免使用这些字段。但如果所有内容都采用单一方法,则可能难以阅读。

答案 1 :(得分:1)

我怀疑你基本上需要某种“一切都好”的标志:

  1. 创建此全局标志,并在测试开始时将其设置为True
  2. 编写一个并行的Assert方法,清除该标志并为“原因”设置另一个变量(或将其添加到列表中)然后干净地退出线程(如果可能)
  3. 让主测试线程等待所有其他线程完成,然后检查标志。
  4. 有些测试框架可能内置了这个,但我不知道有任何副手......

答案 2 :(得分:0)

我尝试过Stefan建议的内容,以下内容适用于我:

public void TestFooMessage() {
    Foo message = null;
    var resetEvent = new AutoResetEvent(false);

    Server.OnReceive += (s, e) => {
         message = e.Message;
         resetEvent.Set();
    };

    var message = new Foo();
    Client.Send(message);

    if (resetEvent.WaitOne(1000)) {
         Assert.IsInstanceOfType(e.Message, typeof(Foo));
    } else {
         Assert.Fail("Foo not received!");
    }
}

谢谢!