“威胁已经被清除了。” 在测试中测试在后台线程上触发委托的代码

pus*_* 22 5 c# multithreading unit-testing

我有一些旧代码,我正在尝试为其编写测试。该代码解析日志文件(在后台线程上),完成后触发传入的委托。

IE

public delegate void finread(LogData l, LRParseState l, string e="");
void Thread_ParseLog(object info) {
  var info = ti as ThreadInfo;
  // some time later
  info.fin(log, state, error);
}
public static void ParseErrorLog(string log, finread fin){
    var pts = new ParameterizedThreadStart(Thread_ParseLog);
    new Thread(pts).Start(new ThreadInfo(log, fin));
}
Run Code Online (Sandbox Code Playgroud)

该代码是生产代码,一切正常,并且已经完成很长时间了,但是当我尝试测试它时,我得到“线程正在中止”。Thread_ParseLog 方法中引发异常。

测试看起来像这样:

void llt(string name, Action<LogData, LRParseState> test) {
    finread d = (LogData l, LRParseState s, string e) => {
      test(l, s);
    };
    LogReader.ParseErrorLog(name, d);
}
[TestMethod]
public void Create_LogReader_Big_Log() {
    llt(ERROR_LOG, (log, state) => {
        Assert.IsTrue(log != null); // never get here!
    });
}
Run Code Online (Sandbox Code Playgroud)

测试数据较大,约55mb,正常处理需要500ms左右。

我还在输出窗口中收到错误:

抛出异常:mscorlib.dll 中的“System.Threading.ThreadAbortException”System.AppDomainUnloadedException:尝试访问已卸载的 AppDomain。如果测试启动了一个线程但没有停止它,就会发生这种情况。确保测试启动的所有线程在完成之前都已停止。

这似乎指出了某种线程同步问题,但我对正在测试的代码无能为力。

显然,这就是我编写测试的方式,我可以通过更改测试来修复它,但我不确定为什么会发生这种情况。

TIA。

Nin*_*rry 7

使用同步机制(例如,ManualResetEvent在离开测试方法之前等待测试的异步部分完成)。

[TestMethod]
public void Create_LogReader_Big_Log() {
    // Use this event to wait until the asynchronous code has been executed 
    // before leaving the test method
    ManualResetEvent resetEvent = new ManualResetEvent(false);
    LogData logDataReceived = null;

    llt(ERROR_LOG, (log, state) => {
        logDataReceived = log;

        // Signal that the test has reached the end
        resetEvent.Set();
    });

    // Wait for the event to be set
    resetEvent.WaitOne();

    // Additionally wait for a grace period to allow the other thread to fully terminate
    Thread.Sleep(500);

    // Now perform the asserts on the received data
    Assert.IsTrue(logDataReceived != null);
}
Run Code Online (Sandbox Code Playgroud)

  • 太好了,工作正常,我将测试编写得更干净,如下所示: void llt(string name, Action&lt;LogData, LRParseState&gt; test) { var mre = new ManualResetEvent(false); finread d = (LogData l, LRParseState s, 字符串 e) =&gt; { test(l, s); mre.set(); }; LogReader.ParseErrorLog(名称, d); mre.WaitOne(); 并且根本不改变实际的测试代码。非常感谢。 (2认同)