slogan3

Ontwikkel strategieën voor het mocken van externe API's in unit tests

description

Met deze prompt leer je hoe je externe API-interfaces effectief kunt mocken binnen je unit tests, waardoor je tests sneller en betrouwbaarder worden zonder dat ze afhankelijk zijn van netwerkcondities. Het helpt je ook om onderhoudsstrategieën te ontwikkelen voor mocks bij API-wijzigingen, wat veel handmatig werk bespaart.

prompt

Help me bij het ontwikkelen van effectieve strategieën voor het mocken van externe API's binnen mijn unit tests. Mijn API-specificaties: <voer hier de specificaties of documentatie van de externe API in>. Beschrijf hoe ik betrouw ...

try_prompt

generate_helper
disclaimerOnPageApi

ai_answers

provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een overzicht van effectieve strategieën voor het mocken van je REST API in Python, inclusief voorbeelden en onderhoudstips: **1. Gebruik van Mocking Libraries** Voor Python kun je bijvoorbeeld `unittest.mock` of gespecialiseerde bibliotheken zoals `responses` of `httpretty` gebruiken. **2. Voorbeeld met `responses`** `responses` maakt het makkelijk om HTTP-verzoeken te mocken zonder netwerkverkeer. *Installatie:* ```bash pip install responses ``` *Voorbeeldcode:* ```python import responses import requests @responses.activate def test_get_users(): # Mock voor GET /users responses.add( responses.GET, 'https://api.example.com/users', json=[{'id': 1, 'name': 'Jan'}], status=200 ) # Uitvoeren van de API-aanroep resp = requests.get('https://api.example.com/users') assert resp.status_code == 200 assert resp.json() == [{'id': 1, 'name': 'Jan'}] ``` **3. Mocken van POST en DELETE requests** Voor POST en DELETE kun je vergelijkbare mocks opzetten: ```python # Mock voor POST /users responses.add( responses.POST, 'https://api.example.com/users', json={'id': 2, 'name': 'Piet'}, status=201 ) # Mock voor DELETE /users/{id} responses.add( responses.DELETE, 'https://api.example.com/users/1', status=204 ) ``` **4. Betrouwbare mocks creëren** - **Consistentie:** Definieer vaste mock-responses die overeenkomen met API-specificaties. - **Parametrisatie:** Gebruik functies om mocks te genereren afhankelijk van testcases. - **Edge-cases:** Voeg mocks toe voor foutmetingen, zoals 404 of 500 statuscodes, om robuuste tests te garanderen. **5. Onderhoud van mocks bij API-updates** - **Versiebeheer:** Documenteer de mock-specs en versieer ze samen met je code. - **Automatisering:** Implementeer tests die controleren of mocks nog overeenkomen met de werkelijke API (bijvoorbeeld via contract testing). - **Regelmatige review:** Controleer periodiek of mocks nog kloppen met de actuele API-implementatie en pas ze aan indien nodig. **Samenvatting:** Gebruik mockingbibliotheken zoals `responses` om je API-aanroepen te simuleren. Definieer consistente en uitgebreide mocks voor alle relevante endpoints en test verschillende scenario’s. Houd mocks up-to-date door ze te documenteren en te integreren in je testproces. Wil je dat ik een volledige voorbeeldtest voor jouw API-specificaties opstel?
provider: deepseek
model: deepseek-chat
Absoluut! Hier is een uitgebreide gids voor het mocken van externe REST API's in je Python unit tests, inclusief strategieën, voorbeelden en onderhoudstips. ### 1. Strategieën voor het Mocken van Externe API's **Core Principe:** Vervang de daadwerkelijke netwerkaanroep door een gesimuleerd antwoord (mock) dat het verwachte gedrag van de echte API nabootst. **Waarom Mocken?** * **Snelheid:** Geen netwerklatentie. * **Betrouwbaarheid:** Tests falen niet door netwerk- of API-storingen. * **Voorspelbaarheid:** Volledige controle over zowel succes- als foutscenario's (bijv. 404, 500 errors). * **Geen Afhankelijkheid:** Tests kunnen draaien zonder internettoegang of credenties. **Aanbevolen Bibliotheken voor Python:** * `unittest.mock` (standaard in Python, krachtig en veelzijdig) * `requests-mock` (specifiek en erg handig voor de `requests` bibliotheek) * `pytest-mock` (een wrapper rond `unittest.mock` voor prettig gebruik met pytest) --- ### 2. Implementatievoorbeelden (Python) Laten we ervan uitgaan dat je een module `api_client.py` hebt die de `requests` bibliotheek gebruikt. **api_client.py:** ```python import requests class UserAPIClient: def __init__(self, base_url): self.base_url = base_url def get_all_users(self): response = requests.get(f"{self.base_url}/users") response.raise_for_status() return response.json() def create_user(self, user_data): response = requests.post(f"{self.base_url}/users", json=user_data) response.raise_for_status() return response.json() def delete_user(self, user_id): response = requests.delete(f"{self.base_url}/users/{user_id}") response.raise_for_status() return response.status_code == 204 ``` #### Voorbeeld 1: Mocken met `unittest.mock` (meest algemene aanpak) **test_api_client.py:** ```python import pytest from unittest.mock import patch, Mock from api_client import UserAPIClient class TestUserAPIClient: BASE_URL = "http://fake-api.test" @patch('api_client.requests.get') # Patch de 'requests.get' methode IN de api_client module def test_get_all_users_success(self, mock_get): # 1. ARRANGE: Stel de mock in mock_response = Mock() expected_users = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}] mock_response.json.return_value = expected_users mock_response.raise_for_status.return_value = None # .raise_for_status() doet niets mock_get.return_value = mock_response # requests.get() retourneert onze mock_response client = UserAPIClient(self.BASE_URL) # 2. ACT: Roep de te testen methode aan users = client.get_all_users() # 3. ASSERT: Controleer resultaat en of de mock correct is aangeroepen assert users == expected_users mock_get.assert_called_once_with(f"{self.BASE_URL}/users") mock_response.raise_for_status.assert_called_once() @patch('api_client.requests.post') def test_create_user(self, mock_post): mock_response = Mock() expected_new_user = {"id": 3, "name": "Charlie"} mock_response.json.return_value = expected_new_user mock_response.raise_for_status.return_value = None mock_post.return_value = mock_response client = UserAPIClient(self.BASE_URL) user_data = {"name": "Charlie"} result = client.create_user(user_data) assert result == expected_new_user # Controleer of post is aangeroepen met de correcte URL en JSON data mock_post.assert_called_once_with(f"{self.BASE_URL}/users", json=user_data) @patch('api_client.requests.delete') def test_delete_user_success(self, mock_delete): mock_response = Mock() mock_response.status_code = 204 # Success, no content mock_response.raise_for_status.return_value = None mock_delete.return_value = mock_response client = UserAPIClient(self.BASE_URL) user_id = 456 result = client.delete_user(user_id) assert result is True mock_delete.assert_called_once_with(f"{self.BASE_URL}/users/{user_id}") @patch('api_client.requests.get') def test_get_all_users_failure(self, mock_get): # Testen van een foutscenario (bijv. 404 Not Found) mock_response = Mock() mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError("404 Client Error") mock_get.return_value = mock_response client = UserAPIClient(self.BASE_URL) # Controleer of dezelfde exception wordt opgeworpen with pytest.raises(requests.exceptions.HTTPError): client.get_all_users() ``` #### Voorbeeld 2: Mocken met `requests-mock` (meer declaratief) Eerst installeren: `pip install requests-mock` **test_api_client_requests_mock.py:** ```python import pytest import requests_mock from api_client import UserAPIClient class TestUserAPIClientWithRequestsMock: BASE_URL = "http://fake-api.test" def test_get_all_users_success(self): client = UserAPIClient(self.BASE_URL) expected_users = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}] # Gebruik de requests_mock context manager with requests_mock.Mocker() as m: # Stel de mock direct in op de exacte URL m.get(f"{self.BASE_URL}/users", json=expected_users, status_code=200) users = client.get_all_users() assert users == expected_users # Controleer of de mock precies één keer is aangeroepen assert m.call_count == 1 def test_create_user(self): client = UserAPIClient(self.BASE_URL) user_data = {"name": "Charlie"} expected_response = {"id": 3, "name": "Charlie"} with requests_mock.Mocker() as m: # Match op POST, URL, en controleer de JSON body m.post(f"{self.BASE_URL}/users", json=expected_response, status_code=201) result = client.create_user(user_data) assert result == expected_response # Optioneel: controleer de request history voor details assert m.last_request.json() == user_data ``` --- ### 3. Tips voor het Onderhouden van Mocks bij API-updates Dit is een kritisch onderdeel. Slecht onderhouden mocks leiden tot vals-positieve tests. 1. **Centraliseer Mock Data:** * Sla mock responses op in aparte JSON-bestanden (bijv., `tests/mock_data/users_get_all.json`) of in dictionaries in een aparte module. * **Voordeel:** Eén plek om data aan te passen. Je tests lezen `json.loads(mock_data.USERS_GET_ALL)` in plaats van hardgecodeerde dictionaries. 2. **Gebruik een Schema-/Contract-Test:** * Schrijf **één geïntegreerde test** die niet mocket, maar daadwerkelijk tegen een bekende testomgeving (QA/Staging) van de API aanpraat. * Deze test valideert of jouw mocks en verwachtingen nog overeenkomen met de werkelijkheid. Draai deze minder frequent (bijv. in een nachtelijke build). * Gebruik bibliotheken zoals `pydantic` om de response van de echte API te valideren tegen een model. 3. **Versionering en Communicatie:** * Houd de API-versie bij die je mocket (bijv. in een commentaar of een config-bestand). * Abonneer je op changelogs of release notes van de API-leverancier. API-updates moeten een directe trigger zijn om je mocks te herzien. 4. **Mock op het Juiste Niveau:** * Mock de **HTTP-bibliotheek** (zoals `requests`), niet je eigen clientmethode. Dit test ook je integratielaag correct. 5. **Automatiseer waar mogelijk:** * Overweeg tools zoals **OpenAPI-generator** of **Postman**. Soms kunnen deze tools automatisch mock servers genereren vanuit je OpenAPI-specificatie, wat een bron van waarheid wordt voor zowel ontwikkeling als testing. 6. **Documenteer je Mocks:** * Noteer bij complexe mocks welke API-versie en welke edge-case ze nabootsen. Dit maakt onderhoud later veel eenvoudiger. **Conclusie:** Door `unittest.mock` of `requests-mock` te gebruiken, isoleer je je tests volledig en maak je ze razendsnel. Het onderhoudsprobleem los je op door mockdata te centraliseren en te investeren in een enkele contracttest die je waarschuwt wanneer de externe API verandert.