How can we mock several exception in Pytest, Mock_Response?

Question:

We’re revising our pytest script, according to parent ‘executor’ method revision — added retry logic, to retry 3 times until get response and raise error on 4th.attempt.

Used to be, we test to raise socket error exception as follows, now we need to raise that exception after 3 times retry (below pytest code encountered the test error now).

-- original code
def test_socketerror(monkeypatch, requests_mock):

    monkeypatch.setenv('ENV_ID', 'Local')
    requests_mock.post("http://localhost:8080/samplejob", exc=socket.error)

    with pytest.raises(CommunicationError) as ce:
        job_id = 'JOB_ID'
        executor = parentjob()
        executor.samplejob(job_id, None, None, None, None)
    assert str(ce.value.args[0]) == "same error message on parent method"

On the other hand, we can revise the other retry test as expected, to add mock_response with multiple response.

-- other test revise (seems working fine)
def test_retry(monkeypatch, requests_mock):

monkeypatch.setenv('ENV_ID', 'Local')
headers = {'content-type': 'application/json'}
mock_response = [
    {'json': {'status': None}, 'status_code': None},
    {'json': {'status': None}, 'status_code': None},
    {'json': {'status': None}, 'status_code': None},
    {'json': {'status': None}, 'status_code': None}
]
requests_mock.post("http://localhost:8080/samplejob", headers=headers, json=mock_response)

with pytest.raises(CommunicationError) as ce:
    job_id = 'JOB_ID'
    executor = parentjob()
    executor.samplejob(job_id, None, None, None, None)
assert str(ce.value.args[0]) == "same error message on parent method"

But for Socket Error exception, can’t apply multiple mock_response.

Let me also add the parent job:

class parent
    
    def parentjob(self, job_id, date, subject, fromDate, toDate):

        for error_count in range(self.error_retry_times):
            try:
                request_url = 'http://' + self.hostname + '/samplejob'
                headers = {'content-type': 'application/json'}
                response = requests.post(request_url, data=json.dumps(payload), timeout=self.timeout, headers=headers)
            except Timeout as te:
                error_message = 'access batch api timeout.jobId=%s, count=%d' % (job_id, error_count)
            except Exception as e:
                error_message = 'failed to access batch api.jobId=%s, count=%d' % (job_id, error_count)

            if response is None:
                time.sleep(self.error_retry_inerval)
            else:
                break

        if response is None or response.status_code != 202:
            error_message = "error message on parent method"
            raise CommunicationError(error_message)

        return response
Asked By: Sachiko

||

Answers:

You can use mocker fixture like so:

def test_retry_exception(mocker):
    mocker.patch("parent_module_path.requests.post", side_effect = [Exception("first time"), Exception("second time"), Exception("third time"), Exception("forth time")])

    with pytest.raises(CommunicationError) as ce:
        job_id = 'JOB_ID'
        executor = parentjob()
        executor.samplejob(job_id, None, None, None, None)
    assert str(ce.value.args[0]) == "same error message on parent method"
Answered By: Peter K

Thanks to the great hint of @Peter K, I successed to raise and test multiple exceptions in requests mock like this;

def test_socketerror(monkeypatch, requests_mock):
    monkeypatch.setenv('ENV_ID', 'Local')
    ***requests_mock.side_effect = (socket.error(),socket.error(),socket.error(),socket.error())
    requests_mock.post("http://localhost:8080/samplejob")***


with pytest.raises(CommunicationError) as ce:
    job_id = 'JOB_ID'
    executor = parentjob()
    executor.samplejob(job_id, None, None, None, None)
assert str(ce.value.args[0]) == "same error message on parent method"

Also, it can be applied for timeout error;

requests_mock.side_effect = (requests.exceptions.Timeout(),requests.exceptions.Timeout(),requests.exceptions.Timeout(),requests.exceptions.Timeout())

Hopefully, it can be little help for someone who has same issue in mock usage.

Answered By: Sachiko
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.