简体   繁体   中英

How to Mock: pytest.raises DID NOT RAISE <class 'subprocess.TimeoutExpired'>

I am using subprocess for a task, and I have a try/except block for catching TimeoutExpired . I try to mock my object using side_effect so I can catch the fake exception with pytest.raises . Whatever I do, I get DID NOT RAISE <class 'subprocess.TimeoutExpired'> . I have tried many things, and even though I'm not so experienced with mocking, I believe something like that should in principle work:

# 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()

For some reason it doesn't work though, and I can't get my head around what's wrong.

If you want to test the functionality of a class ( Check ) you cannot mock that class. You have to mock instead the calls that you want to change - in this case probably check_output , which you want to raise an exception:

@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")

A few notes:

  • you have to patch "src.my_check.check_output", because you import check_output using from subprocess import check_output , so you use the reference in your class
  • you have to construct a valid TimeoutExpired object - it requires 2 arguments, so you have to provide them
  • as get_status is already called in __init__ , you have to test the class construction - you can't get a properly constructed instance because of the raised exception

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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