使 Python 单元测试因任何线程的异常而失败

2024-04-02

我正在使用单元测试框架来自动化多线程 python 代码、外部硬件和嵌入式 C 的集成测试。尽管我公然滥用单元测试框架进行集成测试,但它的效果非常好。除了一个问题:如果任何生成的线程引发异常,我需要测试失败。这可以通过单元测试框架实现吗?

一个简单但不可行的解决方案是 a) 重构代码以避免多线程或 b) 单独测试每个线程。我不能这样做,因为代码与外部硬件异步交互。我还考虑过实现某种消息传递以将异常转发到主单元测试线程。这将需要对正在测试的代码进行与测试相关的重大更改,我想避免这种情况。

是时候举个例子了。我可以修改下面的测试脚本以在 my_thread 中引发的异常上失败吗without修改 x.ExceptionRaiser 类?

import unittest
import x

class Test(unittest.TestCase):
    def test_x(self):
        my_thread = x.ExceptionRaiser()
        # Test case should fail when thread is started and raises
        # an exception.
        my_thread.start()
        my_thread.join()

if __name__ == '__main__':
    unittest.main()

首先,sys.excepthook看起来像是一个解决方案。它是一个全局钩子,每次抛出未捕获的异常时都会调用它。

不幸的是,这不起作用。为什么?出色地threading包裹你的run代码中的函数打印您在屏幕上看到的可爱的回溯(注意到它总是告诉您Exception in thread {Name of your thread here}?这就是它的完成方式)。

从 Python 3.8 开始,您可以重写一个函数来实现此功能:线程.excepthook https://docs.python.org/3/library/threading.html#threading.excepthook

...可以重写 threading.excepthook() 以控制如何处理 Thread.run() 引发的未捕获异常

那么我们该怎么办?用我们的逻辑替换这个函数,并且voilà:

对于Python >= 3.8

import traceback
import threading 
import os


class GlobalExceptionWatcher(object):
    def _store_excepthook(self, args):
        '''
        Uses as an exception handlers which stores any uncaught exceptions.
        '''
        self.__org_hook(args)
        formated_exc = traceback.format_exception(args.exc_type, args.exc_value, args.exc_traceback)
        self._exceptions.append('\n'.join(formated_exc))
        return formated_exc

    def __enter__(self):
        '''
        Register us to the hook.
        '''
        self._exceptions = []
        self.__org_hook = threading.excepthook
        threading.excepthook = self._store_excepthook

    def __exit__(self, type, value, traceback):
        '''
        Remove us from the hook, assure no exception were thrown.
        '''
        threading.excepthook = self.__org_hook
        if len(self._exceptions) != 0:
            tracebacks = os.linesep.join(self._exceptions)
            raise Exception(f'Exceptions in other threads: {tracebacks}')

对于旧版本的 Python,这有点复杂。 长话短说,看来threadingnodule 有一个未记录的导入,它执行以下操作:

threading._format_exc = traceback.format_exc

毫不奇怪,只有当线程抛出异常时才会调用该函数run功能。

所以对于 python

import threading 
import os

class GlobalExceptionWatcher(object):
    def _store_excepthook(self):
        '''
        Uses as an exception handlers which stores any uncaught exceptions.
        '''
        formated_exc = self.__org_hook()
        self._exceptions.append(formated_exc)
        return formated_exc
        
    def __enter__(self):
        '''
        Register us to the hook.
        '''
        self._exceptions = []
        self.__org_hook = threading._format_exc
        threading._format_exc = self._store_excepthook
        
    def __exit__(self, type, value, traceback):
        '''
        Remove us from the hook, assure no exception were thrown.
        '''
        threading._format_exc = self.__org_hook
        if len(self._exceptions) != 0:
            tracebacks = os.linesep.join(self._exceptions)
            raise Exception('Exceptions in other threads: %s' % tracebacks)

Usage:

my_thread = x.ExceptionRaiser()
# will fail when thread is started and raises an exception.
with GlobalExceptionWatcher():
    my_thread.start()
    my_thread.join()
            

你还需要join你自己,但在退出时,with语句的上下文管理器将检查其他线程中抛出的任何异常,并适当地引发异常。


本代码“按原样”提供,不提供任何形式的保证, 明示或暗示

这是一个没有记录的、有点可怕的黑客行为。我在linux和windows上测试了它,似乎可以工作。需要您自担风险使用它。

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

使 Python 单元测试因任何线程的异常而失败 的相关文章

随机推荐

  • 写入器还是输出流?

    我正在设计一个库 其中的类应该能够将自身内部转换为文本 我应该使用哪个类 OutputStream http download oracle com javase 6 docs api java io OutputStream html o
  • 动态地将输入宽度扩展为字符串的长度

    我正在尝试创建一个input至少在宽度上随着用户输入的字符串的长度动态扩展的字段 甚至可能是多行的 这可能吗 input https material angular io components input overviewAngular
  • Excel 中具有层次结构的自动编号

    我想做一个自动汇总编号 我们唯一能做的就是给 A 标题 编号 但字幕应该自动编号 如果标题 1 副标题为 1 1 下方为 1 1 1 依此类推 假设标题 A B 和 C 是副标题 图案应该是这样的 1 A 1 1 B 1 2 B 2 A 2
  • Doctrine 分配错误:无法将 Doctrine\ORM\PersistentCollection 分配给属性

    我有一个上传 我想显示数据库中的所有类别 但我不断收到 EntityType 错误 我不知道为什么之前可以正常工作 这是错误 Cannot assign Doctrine ORM PersistentCollection to proper
  • 如何将子实例反序列化为父对象而不丢失其特定属性?

    下面分几个类 如何序列化 A 实例的 Json 字符串 其中 PropertyB 包含 SpecPropB1 或 SpecPropB2 以便这些属性保留在 C 对象中 public class A public B PropertyB ge
  • 当客户端读取 HashMap 时如何刷新 HashMap

    我有一个静电HashMap在服务器启动时初始化 客户端在登录时从该地图初始化其数据 现在我需要刷新这张地图 但是客户端可以同时登录并从这张地图中获取数据 当他们阅读时 我可以更改如下所示的地图参考吗 我不能使用synchronized因为它
  • jCenter 和 Bintray 正在关闭。怎么办?如果使用第三方库如何解决?

    jCenter 和 Bintray 正在关闭 那么我们该如何解决这个问题 如果项目中使用了第三方库怎么办 请帮帮我 提前致谢 在你所有的build gradle文件替换jcenter by mavenCentral 或者如果 mavenCe
  • 如何在 fxml 项目中使用 font Awesome (javafx)

    我想在我的项目中使用 font Awesome 字体 但我不知道如何在我的项目中使用 font Awesome 我找到了一些示例 但它们不能在 fxml 中使用 很棒的javafx字体 https bitbucket org Jerady
  • 如何根据类的值将类对象添加到 hashMap 中?

    我正在从数据库中检索一些值 这些值需要添加到列表中 然后根据其值添加到具有特定键的 MAP 中 例如 row 1 name A category 1 row 2 name B category 2 row 3 name C category
  • 当我滚动 UIPickerView 时,如何实时获取所选值

    For example in this image when I m scrolling the UIPickerView to 2012 9 28 what I want is that the text of the black lab
  • 如何在 Silverlight 中的 Border 元素上制作虚线边框?

    我怎样才能让这个Border Silverlight元素的底部边框变成红色dotted里面有一个红色的solid line Border border new Border border CornerRadius new CornerRad
  • WPF 图表:如何折叠线系列中的数据点

    我在图表中有多条线系列 首先绘制图表线 然后沿着线绘制点 这很烦人 而且大点的大小使得大型数据集根本毫无用处 目前我正在为每个系列做这个
  • 选择限制功能不适用于reactjs 复选框形式

    我有一个从 json 获取复选框的 React 组件 复选框的每个部分最多可以包含 5 个复选框 我试图将每个部分中的限制设置为最多 2 个选择 但是它没有按应有的方式工作 主要成分是项目列表 js 复选框来自复选框 js 这是我正在尝试做
  • current->mm 在 Linux 内核中给出 NULL

    我想遍历页表 因此我访问了 current gt mm 但它给出了 NULL 值 我正在研究 linux 内核 3 9 我不明白 current gt mm 怎么会为零 这里有什么我想念的吗 这意味着您处于内核线程中 在Linux中 内核线
  • 用MPI发送size_t类型数据

    在 MPI 中发送 size t 类型数字的最安全方法是什么 例如 我确信它是not将其作为 MPI INT 盲目发送是安全的 MPI LONG 总是有效吗 使用宏怎么样 include
  • 选择看起来像错误/缺失功能的重载时,C# 编译器出现奇怪的行为

    我最近发现 C 编译器的一个有趣的行为 想象一下这样的界面 public interface ILogger void Info string operation string details null void Info string o
  • 使用 C 函数扩展 Numpy

    我正在尝试加速我的 Numpy 代码 并决定实现一个特定的函数 而我的代码大部分时间都在 C 中使用 我实际上是 C 的菜鸟 但我设法编写了一个函数 将矩阵中的每一行归一化为 1 我可以编译它 并用一些数据 在 C 中 测试它 它满足了我的
  • 使用 RxJS 将多个 ajax 请求转换为 Observables

    我正在努力解决某件事 我猜这意味着我误解了并且正在做一些愚蠢的事情 我有一个可观察对象 需要使用它来创建一些对象 将其发送到服务器进行处理 将服务器的结果与我发送的对象结合起来 然后将其转换为可观察对象 所以我想要做什么 我认为 就像是 v
  • 具有 http 身份验证的 Zend SOAP 服务器 WSDL URI

    我正在尝试使用 Zend Soap Server 设置 SOAP 服务 ZF1 我的问题是 WSDL URI 受密码保护 可以通过设置 https 用户名 来访问它 电子邮件受保护 cdn cgi l email protection 作为
  • 使 Python 单元测试因任何线程的异常而失败

    我正在使用单元测试框架来自动化多线程 python 代码 外部硬件和嵌入式 C 的集成测试 尽管我公然滥用单元测试框架进行集成测试 但它的效果非常好 除了一个问题 如果任何生成的线程引发异常 我需要测试失败 这可以通过单元测试框架实现吗 一