Solution officielle
class ArticleViewSet:
def __init__(self):
self.db = {}
self.next_id = 1
def list(self):
return {'status': 200, 'data': list(self.db.values())}
def create(self, data):
article = dict(data)
article['id'] = self.next_id
self.db[self.next_id] = article
self.next_id += 1
return {'status': 201, 'data': article}
def retrieve(self, pk):
if pk not in self.db:
return {'status': 404, 'error': 'Non trouve'}
return {'status': 200, 'data': self.db[pk]}
def update(self, pk, data):
if pk not in self.db:
return {'status': 404, 'error': 'Non trouve'}
self.db[pk].update(data)
self.db[pk]['id'] = pk
return {'status': 200, 'data': self.db[pk]}
def destroy(self, pk):
if pk not in self.db:
return {'status': 404, 'error': 'Non trouve'}
del self.db[pk]
return {'status': 204, 'data': None}
def dispatch(self, method, data=None, pk=None):
if method == 'GET' and pk is None:
return self.list()
elif method == 'POST' and pk is None:
return self.create(data)
elif method == 'GET' and pk is not None:
return self.retrieve(pk)
elif method == 'PUT' and pk is not None:
return self.update(pk, data)
elif method == 'DELETE' and pk is not None:
return self.destroy(pk)
return {'status': 405, 'error': 'Méthode non autorisee'}
class APITestClient:
def __init__(self, viewset):
self.viewset = viewset
def _extract_pk(self, path):
parts = path.strip('/').split('/')
if parts and parts[-1].isdigit():
return int(parts[-1])
return None
def get(self, path):
pk = self._extract_pk(path)
return self.viewset.dispatch('GET', pk=pk)
def post(self, path, data=None):
pk = self._extract_pk(path)
return self.viewset.dispatch('POST', data=data, pk=pk)
def put(self, path, data=None):
pk = self._extract_pk(path)
return self.viewset.dispatch('PUT', data=data, pk=pk)
def delete(self, path):
pk = self._extract_pk(path)
return self.viewset.dispatch('DELETE', pk=pk)
def run_api_tests(client):
results = []
passed = 0
failed = 0
tests = [
('GET liste vide', lambda: client.get('/'), lambda r: r['status'] == 200 and r['data'] == []),
('POST crée article', lambda: client.post('/', {'title': 'Test', 'content': 'Body'}), lambda r: r['status'] == 201 and r['data']['title'] == 'Test'),
('GET liste avec 1 article', lambda: client.get('/'), lambda r: r['status'] == 200 and len(r['data']) == 1),
('GET detail article', lambda: client.get('/1/'), lambda r: r['status'] == 200 and r['data']['title'] == 'Test'),
('PUT modifie article', lambda: client.put('/1/', {'title': 'Updated'}), lambda r: r['status'] == 200 and r['data']['title'] == 'Updated'),
('DELETE supprime article', lambda: client.delete('/1/'), lambda r: r['status'] == 204),
]
for name, action, check in tests:
try:
result = action()
success = check(result)
if success:
passed += 1
results.append({'name': name, 'passed': True})
else:
failed += 1
results.append({'name': name, 'passed': False, 'result': result})
except Exception as e:
failed += 1
results.append({'name': name, 'passed': False, 'error': str(e)})
return {'passed': passed, 'failed': failed, 'details': results}