简体   繁体   English

停止当前的 pytest 执行,但继续运行其他情况

[英]Stop current pytest execution but continue to run other cases

I am running tests using pytest on python.我在 python 上使用pytest运行测试。

In the tested code, some conditions trigger a sys.exit(non_zero_code) , using pytest , we want to make sure that sys.exit is called under those conditions, but obviously we do not want the system to really exit, so we mock sys .在测试代​​码中,某些条件触发了sys.exit(non_zero_code) ,使用pytest ,我们希望确保在这些条件下调用sys.exit ,但显然我们不希望系统真正退出,所以我们模拟sys .

The problem is that now, the rest of the code will continue to execute, which I do not want.问题是现在,其余代码将继续执行,这是我不想要的。 If I call pytest.exit , the whole process exit, when I just really want only that test case to stop at this point.如果我调用pytest.exit ,则整个过程都会退出,而我真的只想在此时停止该测试用例。

A good way to visualize is to read this simple example, the "Should not execute, we exited" line will be hit when we run the tests一个很好的可视化方法是阅读这个简单的例子,当我们运行测试时, “不应该执行,我们退出”行将被击中

import os
import sys

import pytest
import logging
from pathlib import Path

logging.basicConfig(filename=os.path.join(Path(__file__).parent.resolve(), "pytest_log"),
                    filemode='a',
                    format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
                    datefmt='%H:%M:%S',
                    level=logging.INFO)
logger = logging.getLogger(__name__)


def function_with_exit(value):

    if value == 2:
        sys.exit(2)
        logger.info("Should not execute, we exited")

    logger.info("Value is not 2")


def side_effect():
    logger.info("Sys exit was called")


@pytest.mark.parametrize("value", [1, 2, 3])
def test_with_pytest(mocker, value):
    mocker.patch(__name__ + '.' + sys.__name__)

    function_with_exit(value)

I need to modify the mock to:我需要将模拟修改为:

  • Not hit the line when the second test case is run运行第二个测试用例时未命中
  • Continue running the next test case继续运行下一个测试用例

Instead of mocking sys.exit() , you should just handle the SystemExit exception it raises:而不是sys.exit() ,您应该只处理它引发的SystemExit异常:

@pytest.mark.parametrize("value", [1, 2, 3])
def test_with_pytest(value):
    try:
        function_with_exit(value)
    except SystemExit:
        pass

From python docs来自 python 文档

Since exit() ultimately “only” raises an exception, it will only exit the process when called from the main thread, and the exception is not intercepted.由于 exit() 最终“只”引发异常,因此只有在从主线程调用时才会退出进程,并且不会拦截异常。 Cleanup actions specified by finally clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.由 try 语句的 finally 子句指定的清理操作得到尊重,并且可以在外部级别拦截退出尝试。

A call to sys.exit() will only create and raise a new SystemExit exception and raise it, This is not inherited from the usual Exception class but from the BaseException class, So it does not get caught with any regular exception handlers, instead they get escalated to the interpreter and interpreter cleans things neatly and exists.sys.exit()的调用只会创建并引发一个新的SystemExit异常并引发它,这不是从通常的Exception类继承的,而是从BaseException类继承的,因此它不会被任何常规异常处理程序捕获,而是它们升级到解释器,解释器整洁地清理事物并存在。

You can catch this in pytest and perform the needed asserts.您可以在 pytest 中捕获它并执行所需的断言。

with pytest.raises(SystemExit) as exc:
    function_with_exit()
    assert exc.value.code == 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM