Help me bij het implementeren van best practices voor het schrijven van onderhoudbare unittests
description
Door deze best practices te volgen, maak je unittests die niet alleen effectief zijn, maar ook gemakkelijker te beheren over de tijd, waardoor technische schuld wordt verminderd en de codekwaliteit verbetert.
prompt
try_prompt
Ik wil ervoor zorgen dat mijn unittests onderhoudbaar zijn en de beste praktijken volgen. Geef me een uitgebreide gids over hoe ik duidelijke, beknopte en effectieve unittests voor mijn projec ... more
generate_helper
...
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Zeker! Hier is een uitgebreide gids voor het schrijven van onderhoudbare, duidelijke en effectieve unittests voor je Python-webapplicatie, inclusief naamgevingsconventies, codeorganisatie en documentatiepraktijken:
### 1. Algemene principes voor goede unittests
- **Isolatie:** Test één stuk functionaliteit per test. Mock externe afhankelijkheden.
- **Repliceerbare tests:** Zorg dat tests altijd hetzelfde resultaat geven, onafhankelijk van omgeving of tijd.
- **Snelle uitvoering:** Tests moeten snel zijn om frequent gebruik te stimuleren.
- **Zelfvoorzienend:** Tests moeten zelfstandig kunnen draaien zonder afhankelijkheden van externe systemen.
### 2. Naamgevingsconventies
- **Testclass-namen:** Gebruik de naam van de klasse of functie gevolgd door `Test`. Bijvoorbeeld: `TestLoginFunctionality`.
- **Testmethoden:** Beschrijf wat de test doet, bijvoorbeeld:
- `test_successful_login`
- `test_invalid_password`
- `test_missing_fields`
- **Gebruik duidelijke, beschrijvende namen** zonder afkortingen, zodat bij het lezen van de testdirect zichtbaar is wat er wordt getest.
### 3. Structuur en organisatie van testcode
- **Mapstructuur:** Plaats je tests in een aparte map, bijvoorbeeld `tests/`.
- **Bestandstructuur:** Maak aparte testbestanden voor verschillende modules, bijvoorbeeld `test_auth.py`, `test_views.py`.
- **Setup en teardown:** Gebruik `setUp()` en `tearDown()` methoden voor herbruikbare setup-code. Overweeg `setUpClass()` en `tearDownClass()` voor klasse-brede setup.
- **Gebruik van fixtures:** Gebruik fixtures of factory-bibliotheken (zoals `pytest fixtures` of `factory_boy`) voor het genereren van testdata.
### 4. Testmethoden schrijven
- **Arrange-Act-Assert:** Volg deze structuur:
- **Arrange:** Bereid je data en omgeving voor.
- **Act:** Voer de actie uit, bijvoorbeeld een functie-aanroep.
- **Assert:** Controleer of het resultaat klopt.
- **Minimaliseer complexiteit:** Houd tests kort en duidelijk, één ding per test.
- **Test verschillende scenario’s:** Positieve en negatieve paden, randgevallen.
### 5. Gebruik van mocking en patching
- **Mock externe systemen:** Bijvoorbeeld databases, API's, bestandsystemen.
- **Gebruik `unittest.mock`:** Bijvoorbeeld `patch()` om functies of klassen te mocken.
- **Vermijd echte externe verbindingen** in unittests, focus op de logica.
### 6. Beveilig je tests tegen flakiness
- **Deterministische tests:** Vermijd tijdsafhankelijke tests.
- **Geen afhankelijkheid van netwerk of externe systemen.**
### 7. Documentatie en commentaar
- **Duidelijke naamgeving:** Zoals eerder genoemd.
- **In-code commentaar:** Leg uit waarom een test bestaat, niet wat de code doet.
- **Gebruik docstrings:** Voeg korte beschrijvingen toe aan testklassen en -methoden:
```python
class TestLoginFunctionality(unittest.TestCase):
"""Testen van het inlogproces van de webapplicatie."""
def test_successful_login(self):
"""Verifieer dat een geldige login succesvol is."""
...
```
- **Testdocumentatie:** Overweeg een overzicht of README te maken met testdoelen.
### 8. Integratie met CI/CD
- **Automatiseer tests:** Integreer met CI/CD pipelines zoals GitHub Actions, GitLab CI, Jenkins.
- **Run alle tests bij elke commit:** Zo voorkom je regressies.
### 9. Gebruik van testframeworks en hulpmiddelen
- **Unittest:** Python’s ingebouwde framework.
- **Pytest:** Meer flexibiliteit en eenvoud.
- **Factory_boy, Faker:** Voor testdata.
- **Coverage.py:** Om testdekking te meten.
### 10. Voorbeeldstructuur
```plaintext
project/
│
├── app/
│ ├── __init__.py
│ ├── views.py
│ ├── models.py
│ └── ...
│
├── tests/
│ ├── __init__.py
│ ├── test_views.py
│ ├── test_models.py
│ └── test_auth.py
│
└── README.md
```
---
### Samenvatting
- Gebruik duidelijke, beschrijvende namen voor testklassen en methoden.
- Organiseer tests logisch en herbruikbaar.
- Schrijf korte, gerichte tests volgens Arrange-Act-Assert.
- Gebruik mocking om afhankelijkheden te isoleren.
- Documenteer je tests met commentaar en docstrings.
- Automatiseer en integreer tests in je ontwikkelproces.
Door deze richtlijnen te volgen, zorg je voor een onderhoudbare en effectieve testsuite die je ontwikkelproces ondersteunt en de kwaliteit van je webapplicatie waarborgt.
provider: deepseek
model: deepseek-chat
### Uitgebreide Gids voor Onderhoudbare Unittests in Python Webapplicaties
#### 1. Basisprincipes van Effectieve Unittests
**FIRST-principes:**
- **Fast**: Tests moeten snel uitvoerbaar zijn (milliseconden per test)
- **Isolated**: Elke test moet onafhankelijk werken
- **Repeatable**: Resultaten moeten consistent zijn
- **Self-validating**: Tests slagen of falen automatisch
- **Timely**: Schrijf tests vóór of tijdens ontwikkeling
#### 2. Naamgevingsconventies
**Testklassen:**
```python
class TestUserService:
class TestAuthenticationMiddleware:
class TestPaymentValidation:
```
**Testmethoden:**
```python
def test_returns_user_when_valid_credentials(self):
def test_raises_authentication_error_when_invalid_token(self):
def test_creates_order_with_correct_total_amount(self):
```
**Bestandsnamen:**
```
test_services.py
test_models.py
test_authentication.py
test_api_endpoints.py
```
#### 3. Teststructuur (AAA-patroon)
```python
def test_user_registration_success(self):
# Arrange
user_data = {
'email': 'test@example.com',
'password': 'securepassword123'
}
user_service = UserService()
# Act
result = user_service.register_user(user_data)
# Assert
assert result.id is not None
assert result.email == user_data['email']
```
#### 4. Testorganisatie
**Mappenstructuur:**
```
project/
├── src/
│ ├── services/
│ ├── models/
│ └── api/
└── tests/
├── unit/
│ ├── services/
│ ├── models/
│ └── api/
├── integration/
└── conftest.py
```
**Fixture-organisatie:**
```python
# conftest.py
import pytest
from src.models import User
@pytest.fixture
def sample_user():
return User(
email='test@example.com',
username='testuser'
)
@pytest.fixture
def authenticated_client():
client = TestClient(app)
client.login(test_user)
return client
```
#### 5. Webapplicatie-specifieke Teststrategie
**API endpoint tests:**
```python
class TestUserAPI:
def test_get_user_returns_200(self, authenticated_client):
response = authenticated_client.get('/api/users/1')
assert response.status_code == 200
def test_create_user_requires_authentication(self, client):
response = client.post('/api/users', json={...})
assert response.status_code == 401
```
**Database tests:**
```python
@pytest.mark.django_db # Voor Django
class TestUserModel:
def test_user_creation(self):
user = User.objects.create(
username='testuser',
email='test@example.com'
)
assert user.pk is not None
```
#### 6. Mocking en Testdoubles
```python
from unittest.mock import Mock, patch
class TestPaymentService:
@patch('services.payment_gateway.charge')
def test_process_payment_calls_gateway(self, mock_charge):
payment_service = PaymentService()
payment_service.process_payment(amount=100, token='tok_123')
mock_charge.assert_called_once_with(100, 'tok_123')
```
#### 7. Testdocumentatie
**Docstrings in tests:**
```python
def test_password_hashing():
"""
Test dat wachtwoorden correct worden gehashed.
Scenario:
- Gebruiker creëert account met wachtwoord
- Wachtwoord moet worden gehashed voordat het wordt opgeslagen
- Origineel wachtwoord mag niet in database staan
"""
# Test implementatie
```
**Testcategorieën:**
```python
@pytest.mark.slow
class TestPerformance:
def test_large_data_processing(self):
# Langzame performance test
pass
@pytest.mark.security
class TestAuthentication:
def test_brute_force_protection(self):
# Security-gerelateerde test
pass
```
#### 8. Onderhoudbare Testpraktijken
**Test Data Factory:**
```python
# tests/factories.py
class UserFactory:
@staticmethod
def create_user(**kwargs):
defaults = {
'username': 'testuser',
'email': 'test@example.com',
'is_active': True
}
defaults.update(kwargs)
return User(**defaults)
```
**Herbruikbare Assertions:**
```python
# tests/assertions.py
def assert_valid_user_response(response):
assert response.status_code == 200
assert 'id' in response.json()
assert 'email' in response.json()
assert 'username' in response.json()
```
#### 9. Testconfiguratie
**pytest.ini:**
```ini
[tool:pytest]
testpaths = tests/unit
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts = --verbose --strict-markers
markers =
slow: langzame tests
integration: integratietests
security: security tests
```
#### 10. Continue Integratie
**GitHub Actions voorbeeld:**
```yaml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: |
pytest --cov=src --cov-report=xml
```
#### 11. Veelgemaakte Fouten om te Vermijden
- **Te veel asserts per test** → Eén duidelijke verantwoordelijkheid
- **Testinterdependentie** → Elke test moet isolaat werken
- **Magic numbers** → Gebruik beschrijvende constanten
- **Over-mocking** → Mock alleen externe afhankelijkheden
- **Testen van implementatiedetails** → Test gedrag, niet implementatie
#### 12. Tools en Libraries
- **pytest**: Primaire testframework
- **factory_boy**: Test data factories
- **freezegun**: Voor tijd-gerelateerde tests
- **responses**: Voor mocking HTTP requests
- **pytest-django**: Django-specifieke testhelpers
Deze aanpak zorgt voor schaalbare, onderhoudbare tests die meegroeien met je webapplicatie en consistent betrouwbare resultaten geven.

