Как издеваться: pytest.raises НЕ ВЫЗЫВАЛTimeoutExpired’>

#python #mocking #subprocess #pytest #try-except

#python #издевательство #подпроцесс #pytest #попробуйте-кроме

Вопрос:

Я использую subprocess для задачи, и у меня есть try/except блок для перехвата TimeoutExpired . Я пытаюсь издеваться над своим объектом, используя side_effect , чтобы я мог поймать поддельное исключение pytest.raises . Что бы я ни делал, я получаю DID NOT RAISE <class 'subprocess.TimeoutExpired'> . Я много чего перепробовал, и хотя у меня нет большого опыта в издевательствах, я считаю, что что-то подобное должно в принципе работать:

 # my_check.py
from subprocess import TimeoutExpired, PIPE, check_output

class Check:
    def __init__(self, name):
        self.name = name
        self.status = self.get_status()

    def get_status(self):
        try:
            out = check_output(["ls"], universal_newlines=True, stderr=PIPE, timeout=2)
        except TimeoutExpired as e:
            print(f"Command timed out: {e}")
            raise

        if self.name in out:
            return True
        return False


# test_my_check.py
import pytest
from unittest import mock
from subprocess import TimeoutExpired

@mock.patch("src.my_check.Check", autospec=True)
def test_is_installed_exception(check_fake):
    check_fake.get_status.side_effect = TimeoutExpired
    obj_fake = check_fake("random_file.txt")
    with pytest.raises(TimeoutExpired):
        obj_fake.get_status()
  

По какой-то причине это не работает, и я не могу понять, что не так.

Ответ №1:

Если вы хотите протестировать функциональность class ( Check ), вы не можете издеваться над этим классом. Вместо этого вам нужно издеваться над вызовами, которые вы хотите изменить — в данном случае, вероятно check_output , над которыми вы хотите вызвать исключение:

 @mock.patch("src.my_check.check_output")
def test_is_installed_exception(mocked_check_output):
    mocked_check_output.side_effect = TimeoutExpired("check_output", 1)
    with pytest.raises(TimeoutExpired):
        Check("random_file.txt")
  

Несколько замечаний:

  • вам нужно исправить «src.my_check.check_output», потому что вы импортируете check_output с помощью from subprocess import check_output , поэтому вы используете ссылку в своем классе
  • вы должны создать допустимый TimeoutExpired объект — для него требуется 2 аргумента, поэтому вы должны их предоставить
  • как get_status уже было вызвано __init__ , вы должны протестировать конструкцию класса — вы не можете получить правильно сконструированный экземпляр из-за возникшего исключения