在 Python 中测试另一个线程的结果时,当断言失败时,PyTest 测试套件会通过吗?

Rob*_*ose 7 python testing multithreading pytest python-multithreading

我目前正在使用 pytest 来测试现有的(根据文档的unittest测试套件)。我目前正在编写一个线程,等待分配 IP 地址,然后将其返回给回调函数,并且我正在编写单元测试来配合它。

这是我编写的测试用例类。

class TestGetIpAddressOnNewThread(unittest.TestCase):

    def test_get_existing_ip(self):
        def func(ip):
            assert ip == "192.168.0.1" # Not the real IP
            # Even when I introduce an assert statement that should fail, test still passes
            assert ip == "shouldn't be the ip" 

        ip_check = GetInstanceIpThread(instance, func)
        ip_check.start()
        ip_check.join()

if __name__ == '__main__':
    pytest.main()
Run Code Online (Sandbox Code Playgroud)

这是GetInstanceIpThread伪定义:

class GetInstanceIpThread(threading.Thread):
    def __init__(self, instance, callback):
        threading.Thread.__init__(self)
        self.event = threading.Event()
        self.instance = instance
        self.callback = callback

    def run(self):
        self.instance.wait_until_running()

        ip = self.instance.ip_address
        self.callback(ip)
Run Code Online (Sandbox Code Playgroud)

当我使用 运行这个测试用例时pytest path_to_file.py::TestGetIpAddressOnNewThread,它通过了(耶!),但即使我引入了断言语句,它也应该 100% 失败(嘘!)。出了什么问题,我如何编写实际上失败的测试?

Rob*_*ose 4

所以我正在回答我自己的问题,因为虽然我能够在 StackOverflow 上找到答案,但它没有任何有用的关键字,因为大多数答案都在讨论如何使用 进行多线程测试pytest-xdist,而不是测试多线程。我最终在调试过程中使用了此处pytest -s path_to_file.py::TestGetIpAddressOnNewThread提到的内容,这表明我有一个由拼写错误引起的异常正在打印,但不会导致测试失败。

这让我想到了这个问题,我最初驳回了这个问题,因为我没有意识到断言只是引发 AssertError 。

因此,我调整了社区 wiki 答案如下,以使断言正常工作!

class GetInstanceIpThread(threading.Thread):
    def __init__(self, instance, callback=None):
        threading.Thread.__init__(self)
        self.event = threading.Event()
        self.instance = instance
        self.callback = callback

    def _run(self):
        # The original run code goes here
        self.instance.wait_until_running()

        ip = self.instance.ip_address
        self.callback(ip)

    def run(self):
        self.exc = None
        try:
            self._run()
        except BaseException as e:
            self.exc = e

    def join(self):
        super(GetInstanceIpThread, self).join()
        if self.exc:
            raise self.exc
Run Code Online (Sandbox Code Playgroud)

请注意,只要其他线程中存在任何异常,您的测试就会失败。这可能不是您想要的,因此如果您只想在断言失败或类似情况下失败,您可以更改BaseExceptionAssertError(或任何您想要失败的内容)。

覆盖join()是必要的,因为您必须在 pytest 的主线程上引发异常,才能使其正确地使测试失败。