Mocking an external API call in a Django view test

Question:

I have written a view in Django that receives text from the user and calls an external API for that text to be translated.

View function:

def translate_view(request):

    if request.method == 'POST':
        form = InputForm(request.POST)
        if form.is_valid():

            source_lang = form.cleaned_data["source_lang"]
            target_lang = form.cleaned_data["target_lang"]
            source_text = form.cleaned_data["source_text"]

            deepl_result = call_deepl_api(source_text, source_lang, target_lang)
 
            return render(
                request,
                "output.html",
                {
                    "source_lang": source_lang,
                    "target_lang": target_lang,
                    "source_text": source_text,
                    "deepl_result": deepl_result,
                },
            )
    else:
        form = InputForm()
    return render(request, 'input.html', {'form': form})

I would like to test this view, and I think I have made the beginner’s mistake of actually calling the API in my tests (they are very slow). As far as I understand it looks like I should mock the external API call, but I am struggling to understand how to do this. Could somebody teach me how to do this for the above view? Any help would be much appreciated!

Tests:

class TestOutput(SimpleTestCase):

    def setUp(self):
        self.valid_data_response = self.client.post(
            reverse('home'),
            {'direction': 'Ja>En', 'source_text': '花粉飛散情報',}
        )

    def test_output_page_status_code_with_valid_data(self):
        self.assertEqual(self.valid_data_response.status_code, 200)

    ... more tests
Asked By: shikamaru

||

Answers:

In case this is useful to anyone else, I was able to solve this with the following.

Here, the views.py file contains the view function "translate_view()" shown in the question, and also a "call_deepl_api()" utility/helper function. Below, the call_deepl_api() function is mocked.

from unittest.mock import patch

class TestOutput(SimpleTestCase):

    def setUp(self):

        with patch('your_app.views.call_deepl_api') as mock_deepl_call:

            deepl_result, deepl_usage = 'Pollen dispersal information', 6
            mock_deepl_call.return_value = deepl_result, deepl_usage

            self.response = self.client.post(
                reverse('home'),
                {'direction': 'Ja>En', 'source_text': '花粉飛散情報'}
            )

            # Assert that mocked function is actually called.
            mock_deepl_call.assert_called_once()

    def test_output_page_response_status_code(self):
        self.assertEqual(self.response.status_code, 200)

    ... more tests
Answered By: shikamaru
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.