D Emma
D Emma

Reputation: 317

Mock Multiple API Requests Separately in Python Unit Tests

I have Flask views.py unit test that calls the other REST API. How can I specifically mock one of the requests?

The reason is one of the requests will trigger some operations, such as commit to database, overwrite to a file, etc, if the status code is 200. I want to check if the status code would return 200. If yes, I want to prevent the subsequent operations in unit test, and if not, it's not hitting any subsequent operation anyways so no worries.

I also want the mocked request does not affect the Flask app request at all, i.e. the Flask app request is not being mocked.

project/views.py

from flask import Flask
from project.another_dir.another_script import another_function

app = Flask(__name__)

@app.route('/api/abcde', methods=['POST'])
def post_something():
    another_function()

project/another_dir/another_script.py

import requests

def another_function():
    response = requests.post(<some_url>)    # this is the "requests" I want to mock

    if response.status_code == 200:
        # server working properly, commit database transaction / write to a file / trigger some other functions / ...
    else:
        # something's wrong with the server, send error for exception handling

Unit test

from unittest.mock import Mock
import pytest

headers = {'Authorization': 'Basic akd39K045Pw=='}
data = "some_data"

@pytest.fixture
def client():
    app.testing = True
    client = app.test_client()

    return client

@pytest.mark.parametrize("h, d, status_code", [
    (None, None, 401),  # no auth header, no data
    (None, data, 401),    # no auth header
    (headers, data, 200)  # with auth header and data
])
def test_views_post_something(client, h, d, status_code):

    ##### This is what I want to mock to avoid actually committing to db
    # from project.another_dir.another_script import requests
    # mock_request = Mock()
    # requests = mock_request
    ##### But no luck

    response = client.post('/api/abcde', headers=h, data=d)

    assert response.status_code == status_code

Upvotes: 2

Views: 2031

Answers (1)

Mike
Mike

Reputation: 806

Have you tried pook and unmock? They serve different use cases, but in this case it sounds like pook is a better fit. Pook works well if the request you're mocking will not change that much and is of a private/internal API

Another option is to use a tool like docker-compose to spin up an ephemeral stack with your database of choice. That way, you can let the request execute without touching any fragile resources, but this tends to be slower and prone to errors if you are trying to recreate complicated states. I usually start with a more low-touch approach like pook or unmock and then build out an ephemeral stack for the most mission-critical tests.

Upvotes: 3

Related Questions