Как отстаивать как UserWarning, так и SystemExit в pytest - PullRequest
1 голос
/ 28 сентября 2019

Утверждение UserWarning и SystemExit в pytest

В моем приложении есть функция, которая при неправильных значениях аргумента вызывает модуль UserWarnings из warnings, а затем вызывает SystemExit из sys модуля.

Код выглядит примерно так:

def compare_tags(.....):

    requested_tags = user_requested_tags # as list
    all_tags = tags_calculated_from_input_file  # as list 

    non_matching_key = [x for x in requested_tags if x not in all_tags]

    # if user requested non existing tag then raise warning and then exit 
    if len(non_matching_key) > 0:

        # generate warning
        warnings.warn("The requested '%s' keys from '%s' is not present in the input file. Please makes sure the input file has the metadata of interest or remove the non matching keys." %(non_matching_key, given_tags))

        # raise system exit
        sys.exit(0)

написание pytest для вышеуказанной функции

Я хочу проверить это UserWarning и SystemExit в pytest одновременно.Я могу проверить SystemExit в pytest как.

with pytest.raises(SystemExit):
    compare_tags(....)

, но это также выдаст предупреждающее сообщение (которое не является ошибкой).

Если я хочу проверить предупреждения:

pytest.warns(UserWarning, 
    compare_tags(...)

Это приведет к ошибке SystemExit, потому что эта вызываемая функция вызовет выход из системы.

Как я могу поставить оба чека warnings и SystemExit в один и тот же pytest?

Ответы [ 2 ]

2 голосов
/ 28 сентября 2019

pytest.warns и pytest.raises являются обычными менеджерами контекста и могут быть объявлены в одном операторе with, если они разделены запятой (см. составные операторы ):

with pytest.warns(UserWarning), pytest.raises(SystemExit):
    compare_tags(...)

, что фактически совпадает с написанием

with pytest.warns(UserWarning):
    with pytest.raises(SystemExit):
        compare_tags(...)

Обратите внимание, что порядок имеет значение - когда вы устанавливаете оба диспетчера контекста в обратном порядке:

with pytest.raises(SystemExit), pytest.warns(UserWarning):
    ...

это то же самое, что и запись

with pytest.raises(SystemExit):
    with pytest.warns(UserWarning):
        ...

Проблема здесь в том, что pytest.raises перехватывает все возникшие ошибки и затем проверяет, что было зафиксировано.Это включает в себя то, что поднимает pytest.warns.Это означает, что

with pytest.raises(SystemExit), pytest.warns(UserWarning):
    sys.exit(0)

пройдет, потому что ошибка, возникшая в pytest.warns, будет проглочена в pytest.raises, тогда как

with pytest.warns(UserWarning), pytest.raises(SystemExit):
    sys.exit(0)

завершится с ошибкой, как и ожидалось.

1 голос
/ 28 сентября 2019

Вы можете вложить два исключения, как это:

def test_exit():
    with pytest.raises(SystemExit):
        error_msg = "warning here"
        with pytest.warns(UserWarning, match = error_msg):
            compare_tags(...)
...