NUnit 异步测试导致 AppDomainUnloadedException

2023-12-21

我有一个带有异步操作的 .NET 4.5 WCF 服务。我进行了集成测试,它使用 NetNamedPipeBinding 构建服务主机并通过客户端进行操作。

然而,每次这样的测试总是会导致 NUnit 报告以下内容:

System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. 
This can happen if the test(s) started a thread but did not stop it. 
Make sure that all the threads started by the test(s) are stopped before completion.

在我看来一切都很好。谁能看出可能是什么原因造成的?我在 GitHub 上有完整的代码示例:https://github.com/devlife/codesamples https://github.com/devlife/codesamples


我也有同样的问题。看起来问题似乎出在 WCF 用来处理异步 IO 的“宽松”完成端口线程(在线程池中)。

When ServiceHost.Close()使用时,它将向所有那些线程发出工作已完成的信号,但它们不会立即消失,也就是说,它们可能比线程结束还存活。ServiceHost.Close()手术。因此,由于测试运行结束,“关闭”过程与 NUnit 引起的实际 AppDomain 卸载发生竞争。

基本上,一个简单的Thread.Sleep(<a couple of seconds>)之后ServiceHost.Close()“修复”这个:-)

在互联网上进行了大量搜索之后,我找不到针对此问题的可靠解决方案(对于一系列类似的问题,但并非全部都是由于相同的原因,谷歌“单元测试appdomainunloadedexception”),缺乏某种方法来抑制这个警告本身。

我尝试了不同的绑定和传输(包括空传输 http://www.codeproject.com/Articles/20709/NullTransport-for-WCF),但没有效果。

最后我选择了这个“解决方案”:

static void PreventPrematureAppDomainUnloadHack()
{
    //
    // When NUnit unloads the test AppDomain, the WCF started IO completion port threads might
    // not have exited yet.
    // That leads to AppDomainUnloadedExceptions being raised after all is said and done.
    // While native NUnit, ReSharper oder TestDriven.NET runners don't show these, VSTest (and
    // TFS-Build) does. Resulting in very annoying noise in the form of build/test warnings.
    //
    // The following code _attempts_ to wait for all completion port threads to end. This is not
    // an exact thing one can do, however we mitigate the risk of going wrong by several factors:
    // (1) This code is only used during Unit-Tests and not for production code.
    // (2) It is only called when the AppDomain in question is about to go away anway.
    //     So the risk of someone starting new IO threads while we're waiting is very
    //     low.
    // (3) Finally, we have a timeout in place so that we don't wait forever if something
    //     goes wrong.
    //
    if (AppDomain.CurrentDomain.FriendlyName.StartsWith("test-domain-", StringComparison.Ordinal))
    {
        Console.WriteLine("AppDomainUnloadHack: enabled (use DbgView.exe for details).");
        Trace.WriteLine(string.Format("AppDomainUnloadHack: enabled for domain '{0}'.", AppDomain.CurrentDomain.FriendlyName));

        AppDomain.CurrentDomain.DomainUnload += (sender, args) =>
        {
            int activeIo;
            var sw = Stopwatch.StartNew();
            var timeout = TimeSpan.FromSeconds(3);

            do
            {
                if (sw.Elapsed > timeout)
                {
                    Trace.WriteLine("AppDomainUnloadHack: timeout waiting for threads to complete.");
                    sw.Stop();
                    break;
                }

                Thread.Sleep(5);

                int maxWorkers;
                int availWorkers;
                int maxIo;
                int availIo;
                ThreadPool.GetMaxThreads(out maxWorkers, out maxIo);
                ThreadPool.GetAvailableThreads(out availWorkers, out availIo);
                activeIo = maxIo - availIo;

                Trace.WriteLine(string.Format("AppDomainUnloadHack: active completion port threads: {0}", activeIo));

            } while (activeIo > 0);

            Trace.WriteLine(string.Format("AppDomainUnloadHack: complete after {0}", sw.Elapsed));
        };
    }
}

3 秒的超时是完全任意的,每次重试之间的 5 毫秒的等待也是任意的。有时我确实会遇到“超时”,但大多数时候它都有效。

我确保每个测试程序集都调用此代码一次(即通过引用类型的静态构造函数)。

像往常一样,在这种情况下YMMV。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NUnit 异步测试导致 AppDomainUnloadedException 的相关文章

随机推荐

  • 我可以用 make 或 new 在 golang 中制作预填充字符串吗?

    我正在尝试优化 Go 中的 stringpad 库 到目前为止 我发现用已知字符值 例如 0 或 填充字符串 实际上是 bytes Buffer 的唯一方法是使用 for 循环 代码片段是 PadLeft pads string on le
  • 如何“锁定键盘”以防止在 X11/Linux/Gnome 上发送更多按键?

    我正在用 python 为 Ubuntu Linux 编写一个反 RSI 打字中断程序 我希望能够 锁定键盘 以便忽略所有按键 直到我 解锁 它 我希望能够强制用户暂停打字 我想要一些编程方式来 关闭 键盘 几乎立即 直到我的程序稍后释放它
  • 带有下划线的 scala 传递函数产生一个函数而不是一个值

    您好 我正在编写将函数传递给映射的任何可能的变体 我最初的理解是它们都会产生相同的结果 但我发现第 2 3 行实际上产生了不同的输出 而第 4 行对我来说是个谜 def g v Int List v 1 v v 1 val l List 1
  • 在 read_excel 中保留特定列

    我正在将 Excel 文件导入到 R 中 我只想保留 A 列和 C 列而不是 B 列 列按顺序为 A B C 但以下代码也保留 B 列 如何在不使用另一行代码子集的情况下删除 B 列 df lt read excel df xlsm fut
  • WPF 过滤列表框

    我有一个ListBox绑定到字符串列表 我想在输入文本时过滤列表TextBox 我该怎么做 public void ListLoad ElementList new List
  • 如何将字符串从 Haskell 传递到 C?

    我想做的就是将纯文本字符串从 Haskell 传递到 C 但是 它表示 Char 是不可接受的返回类型 我无法在任何地方找到他们认为的原因 也找不到可接受的返回类型 我正在尝试制作一个非常简单的操作系统映像 我可以使用 Qemu 启动它 有
  • 确保容量在 Java 中如何工作?

    StringBuffer buff1 new StringBuffer tuts point System out println Old Capacity of buff1 buff1 capacity buff1 ensureCapac
  • Linux 上的 Swift:迈出第一步

    我对斯威夫特完全陌生 它刚刚作为 Linux 的开源版本发布 我想尝试一下 这是在 ubuntu 14 04 上 clang 已根据先决条件安装
  • 添加过多 ID 对 html / js 渲染性能的影响

    我目前正在进行的一个项目大约有 10 个 UL 每个 UL 包含 10 50 个元素 建议每个元素都有一个指定的唯一 ID 我们将使用它通过 Javascript 更新内容 这看起来需要向页面添加大量 ID 但每个字段都会有一个真实且有意义
  • Flutter 上的简单可扩展列也不会具有“标题”>“可扩展”

    我正在尝试制作一个可扩展的列 也就是说 它有 2 个子项 子项和展开小部件时出现的子项 在下图中 您可以看到子项 蓝色 和展开的子项 红色 它们仅应在Expand gt 单击按钮 一切正常 但无论我做什么 我都无法得到Expand gt 按
  • Oracle 如果行不存在则插入

    insert ignore into table1 select value1 value2 from table2 where table2 type ok 当我运行这个时 我收到错误 缺少 INTO 关键字 当我运行这个时 我收到错误
  • HBase 表上的 SparkSQL

    任何人都直接在 HBase 表上使用 SparkSQL 就像在 Hive 表上使用 SparkSQL 一样 我是spark新手 请指导我如何连接hbase和spark 如何查询hbase表 AFAIK 有 2 种方法连接到 hbase 表
  • iOS - 使用 AVPlayer 检测 URL 流是否正常工作

    这就是我的代码中从 url 播放的样子 private func play let streamUrl let playerItem AVPlayerItem url streamURL radioPlayer AVPlayer playe
  • ls | 的输出厕所-l

    通常输出为wc l命令给出文件中的行数 但是 当我们通过管道输出ls命令它 它似乎正确显示当前工作目录中的文件和目录以及链接的数量 我的问题是输出ls命令在同一行中显示某些文件和目录的名称 那么 为什么在这种情况下使用ls wc l与相比
  • 如何使用 Powershell 更改文件的属性?

    我有一个 Powershell 脚本 可以将文件从一个位置复制到另一个位置 复制完成后 我想清除源位置中已复制的文件的存档属性 如何使用 Powershell 清除文件的 Archive 属性 您可以使用旧的 dos attrib 命令 如
  • 以编程方式更改 ABAddressBook、ABPersonCopyArrayOfAllLinkedPeople 中的链接联系人数组

    是否可以通过编程方式添加 删除 CFArray 返回的联系人ABPersonCopyArrayOfAllLinkedPeople 因此 有效地链接和取消链接来自不同来源的不同联系人记录 以在 iOs 电话簿中显示为 统一 据我所知 至少在
  • 如何在java中打开第2层原始套接字?

    如何在java中打开第2层原始套接字 在 C 中 我们通常使用 AF PACKET 级别来打开具有 sockaddr ll 结构的第 2 层原始套接字 二层编程对应的socket包是什么 使用普通的 Java 方法这是不可能的 因为 Jav
  • 使用 nuxtJS + Vue2-Editor 时如何解决文档未定义错误?

    我正在尝试使用 vue2 editor 设置 nuxtjs 应用程序 如果我尝试通过客户端导航导航到编辑器页面 则其加载但如果我直接访问或刷新 例如 com editor 页面 我收到文档未定义错误 我已经识别出它是因为 vue2 编辑器不
  • 如何交换 observableArray 中的两个项目?

    我有一个按钮 可以将 observableArray 中的项目向左移动一个位置 我正在按照以下方式进行操作 然而 缺点是categories index 被从数组中删除 从而丢弃了该节点上的任何DOM操作 在我的例子中是通过jQuery验证
  • NUnit 异步测试导致 AppDomainUnloadedException

    我有一个带有异步操作的 NET 4 5 WCF 服务 我进行了集成测试 它使用 NetNamedPipeBinding 构建服务主机并通过客户端进行操作 然而 每次这样的测试总是会导致 NUnit 报告以下内容 System AppDoma