Kiểm Tra API Django REST Framework: Hướng Dẫn Chi Tiết

INEZA Felin-Michel

INEZA Felin-Michel

22 tháng 5 2026

Kiểm Tra API Django REST Framework: Hướng Dẫn Chi Tiết

Apidog cho doanh nghiệp

Triển khai tại chỗ

SSO & RBAC

Tuân thủ SOC 2

Khám phá Apidog Enterprise

Django REST Framework, thường được viết tắt là DRF, là bộ công cụ tiêu chuẩn để xây dựng API trên nền Django. Nó cung cấp cho bạn serializers, viewsets, routers và một lớp xác thực. Điều mà nó cũng cung cấp, và nhiều nhà phát triển thường ít sử dụng, là một lớp kiểm thử vững chắc được xây dựng dựa trên test runner của chính Django.

Hướng dẫn này sẽ chỉ cho bạn cách kiểm thử API của DRF theo hai cách. Thứ nhất, các bài kiểm thử tự động được viết bằng Python sử dụng APITestCaseAPIClient của DRF, chạy mà không cần máy chủ trực tiếp và phát hiện các lỗi hồi quy (regressions) trên mỗi lần commit. Thứ hai, kiểm tra các endpoint đang chạy bằng một API client, đây là cách bạn khám phá hành vi và xác minh dịch vụ thực tế. Cả hai đều quan trọng, và chúng phát hiện các vấn đề khác nhau.

Thiết lập dự án và môi trường kiểm thử

Bắt đầu với một môi trường cô lập để các dependency kiểm thử tách biệt với phần còn lại của hệ thống của bạn:

python -m venv venv
source venv/bin/activate
pip install django djangorestframework coverage

Một dự án DRF được kiểm thử giống như bất kỳ dự án Django nào khác. Theo quy ước, các bài kiểm thử nằm trong một tệp tests.py bên trong mỗi ứng dụng, hoặc trong một gói tests/ nếu bạn có nhiều bài kiểm thử. Test runner của Django sẽ phát hiện bất kỳ lớp nào kế thừa từ một biến thể của TestCase và bất kỳ phương thức nào có tên bắt đầu bằng test_.

Lựa chọn quan trọng là sử dụng lớp cơ sở nào. unittest.TestCase thuần túy không có cơ sở dữ liệu. TestCase của Django gói mỗi bài kiểm thử trong một giao dịch và hoàn tác nó, do đó các bài kiểm thử không gây ảnh hưởng lẫn nhau. APITestCase của DRF mở rộng TestCase của Django và thay thế client bằng APIClient của DRF, client này hiểu các cơ chế xác thực và loại nội dung của DRF. Đối với công việc API, hãy sử dụng APITestCase.

Có một lớp nữa đáng để biết. TransactionTestCase không gói các bài kiểm thử trong một giao dịch, điều này cần thiết khi mã đang được kiểm thử tự quản lý giao dịch hoặc dựa vào các tính năng cơ sở dữ liệu mà một giao dịch bao bọc sẽ che giấu. Nó chậm hơn vì nó cắt bớt các bảng giữa các bài kiểm thử thay vì hoàn tác, vì vậy chỉ nên sử dụng khi TestCase thực sự không thể mô hình hóa hành vi. Đối với phần lớn các bài kiểm thử endpoint, APITestCase là lựa chọn phù hợp và nhanh nhất.

Việc suy nghĩ về dữ liệu kiểm thử sớm cũng hữu ích. Sử dụng phương thức setUp để tạo các hàng mà mỗi bài kiểm thử trong một lớp cần, hoặc setUpTestData nếu dữ liệu chỉ đọc và có thể được chia sẻ giữa các lớp để tăng tốc. Đối với các dự án lớn hơn, một thư viện factory như factory_boy tạo ra các thể hiện model hợp lệ mà bạn không cần phải chỉ rõ từng trường, giúp các bài kiểm thử ngắn gọn và linh hoạt khi một model có thêm trường bắt buộc mới.

Kiểm thử serializers dưới dạng các đơn vị

Serializers thực hiện xác thực và chuyển đổi giữa các thể hiện model và JSON. Chúng nhỏ gọn và thuần khiết, điều này làm cho chúng lý tưởng cho các bài kiểm thử đơn vị nhanh mà không cần chạm đến các endpoint.

Giả sử bạn có một model Article và một ArticleSerializer. Một bài kiểm thử đơn vị sẽ kiểm tra rằng dữ liệu hợp lệ được chấp nhận và dữ liệu không hợp lệ bị từ chối:

from django.test import TestCase
from articles.serializers import ArticleSerializer


class ArticleSerializerTests(TestCase):

    def test_valid_data_passes(self):
        data = {"title": "Caching strategies", "body": "Use ETags."}
        serializer = ArticleSerializer(data=data)
        self.assertTrue(serializer.is_valid())

    def test_missing_title_fails(self):
        data = {"body": "No title here."}
        serializer = ArticleSerializer(data=data)
        self.assertFalse(serializer.is_valid())
        self.assertIn("title", serializer.errors)

Các bài kiểm thử này chạy trong vài mili giây vì không có HTTP và không có view. Chúng cho bạn biết các quy tắc xác thực là đúng trước khi bạn xem xét đến endpoint. Mức độ bao phủ cấp đơn vị này là cơ sở của kim tự tháp kiểm thử được mô tả trong kiểm thử tự động là gì.

Kiểm thử endpoint với APITestCase và APIClient

Các bài kiểm thử endpoint kiểm tra toàn bộ đường dẫn: định tuyến, view, serializer và phản hồi. APIClient của DRF gửi các yêu cầu trong tiến trình, vì vậy không có máy chủ nào chạy và các bài kiểm thử vẫn nhanh.

from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from articles.models import Article


class ArticleEndpointTests(APITestCase):

    def setUp(self):
        Article.objects.create(title="First post", body="Hello world")

    def test_list_articles_returns_200(self):
        url = reverse("article-list")
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data), 1)

    def test_create_article(self):
        url = reverse("article-list")
        payload = {"title": "Second post", "body": "More content"}
        response = self.client.post(url, payload, format="json")
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Article.objects.count(), 2)

Một vài chi tiết đáng chú ý. self.client là một thể hiện của APIClient được cung cấp bởi APITestCase. Sử dụng reverse() với tên route thay vì mã hóa cứng các URL, để việc thay đổi route không làm hỏng mọi bài kiểm thử. Truyền format="json" khi ghi để client tuần tự hóa payload một cách chính xác. Khẳng định mã trạng thái với các hằng số được đặt tên từ rest_framework.status, vì chúng dễ đọc hơn các số thô. Các mã trạng thái được đề cập trong hướng dẫn về các mã trạng thái HTTP mà REST API nên sử dụng.

Kiểm thử xác thực và quyền hạn

Hầu hết các API thực đều bảo vệ các endpoint của chúng. Bạn cần các bài kiểm thử chứng minh rằng các yêu cầu không được xác thực bị từ chối và các yêu cầu được xác thực với quyền hạn phù hợp sẽ thành công.

APIClient cung cấp hai cách để xác thực một bài kiểm thử. force_authenticate() bỏ qua kiểm tra thông tin đăng nhập và gắn trực tiếp một người dùng, điều này lý tưởng để kiểm thử logic view. login() hoặc credentials() thực thi đường dẫn xác thực thực tế. Dưới đây là một bài kiểm thử quyền hạn sử dụng cả hai hướng:

from django.contrib.auth.models import User
from rest_framework import status
from rest_framework.test import APITestCase
from django.urls import reverse


class ArticlePermissionTests(APITestCase):

    def setUp(self):
        self.user = User.objects.create_user(
            username="editor", password="testpass123"
        )
        self.url = reverse("article-list")

    def test_anonymous_cannot_create(self):
        payload = {"title": "Blocked", "body": "Should fail"}
        response = self.client.post(self.url, payload, format="json")
        self.assertEqual(
            response.status_code, status.HTTP_403_FORBIDDEN
        )

    def test_authenticated_user_can_create(self):
        self.client.force_authenticate(user=self.user)
        payload = {"title": "Allowed", "body": "Should pass"}
        response = self.client.post(self.url, payload, format="json")
        self.assertEqual(
            response.status_code, status.HTTP_201_CREATED
        )

Bài kiểm thử đầu tiên xác nhận lớp quyền hạn chặn các thao tác ghi ẩn danh. Bài kiểm thử thứ hai xác nhận người dùng đã xác thực được chấp nhận. Cùng nhau, chúng xác định ranh giới quyền hạn, đây chính là loại hành vi thường dễ bị lỗi một cách lặng lẽ trong quá trình tái cấu trúc (refactor). Nếu bạn đang kiểm thử xác thực token cụ thể, hãy thay thế force_authenticate bằng self.client.credentials(HTTP_AUTHORIZATION="Token " + token) để thực thi đường dẫn header thực tế.

Điều đáng lưu ý là nên sử dụng cái nào. force_authenticate nhanh hơn và cô lập logic view, vì vậy nó phù hợp với phần lớn các bài kiểm thử quyền hạn nơi bạn chỉ quan tâm đến việc một vai trò có thể hoặc không thể làm gì đó. Đường dẫn thông tin đăng nhập thực tế là những gì bạn muốn cho một tập hợp nhỏ hơn các bài kiểm thử cụ thể chứng minh cơ chế xác thực hoạt động: rằng một token xấu bị từ chối, rằng một token hết hạn thất bại, rằng endpoint đăng nhập phát hành một token có thể sử dụng được. Việc kết hợp cả hai mang lại cho bạn phạm vi bao phủ rộng với chi phí thấp và phạm vi bao phủ sâu ở những nơi quan trọng.

Đừng quên quyền hạn cấp đối tượng. Nhiều API DRF cho phép người dùng chỉnh sửa bản ghi của chính họ nhưng không phải của người khác. Kiểm thử điều đó một cách rõ ràng: tạo hai người dùng, cho một người tạo một bản ghi, sau đó xác nhận người dùng khác nhận được mã 403 hoặc 404 khi cố gắng sửa đổi nó. Các endpoint liệt kê cũng cần được kiểm tra kỹ lưỡng tương tự, vì một queryset bị lỗi có thể trả về các hàng mà người dùng không bao giờ nên thấy ngay cả khi endpoint chi tiết đã bị khóa.

Chạy bộ kiểm thử và đo lường độ bao phủ

Chạy mọi bài kiểm thử với runner của Django:

python manage.py test

Runner phát hiện các lớp kiểm thử của bạn, thiết lập một cơ sở dữ liệu kiểm thử dùng một lần, chạy mỗi bài kiểm thử bên trong một giao dịch và hoàn tác sau đó. Một lần chạy sạch sẽ in ra OK. Một lỗi sẽ hiển thị khẳng định đã bị hỏng và ở đâu.

Việc biết bộ kiểm thử thành công không giống với việc biết nó có đủ độ bao phủ. Công cụ coverage đo lường các dòng mã thực sự đã chạy:

coverage run --source='.' manage.py test
coverage report
coverage html

Báo cáo liệt kê từng tệp với phần trăm các dòng đã được thực thi. Đầu ra HTML làm nổi bật các dòng chưa được kiểm thử bằng màu đỏ, điều này giúp bạn trực tiếp nhận ra các khoảng trống. Hãy đặt mục tiêu bao phủ có ý nghĩa đối với các view, serializer và quyền hạn thay vì một con số tổng quát duy nhất. Bài viết về cách viết script kiểm thử tự động đề cập đến những yếu tố làm cho một bài kiểm thử đáng được giữ lại, vì độ bao phủ của các bài kiểm thử yếu không phải là sự an toàn thực sự.

Kiểm thử API trực tiếp với một client

Các bài kiểm thử Python tự động nhanh và chạy trong CI, nhưng chúng thực thi ứng dụng trong tiến trình. Chúng không phát hiện các vấn đề chỉ xuất hiện khi chạy dịch vụ: một tiêu đề CORS bị cấu hình sai, một proxy ngược loại bỏ một cái gì đó, một cơ sở dữ liệu chậm dưới tải thực tế, hoặc sự khác biệt giữa cơ sở dữ liệu kiểm thử và môi trường sản xuất của bạn. Để làm được điều đó, bạn gửi các yêu cầu thực tế đến các endpoint đã triển khai.

Apidog rất phù hợp ở đây. Đây là một nền tảng API tất cả trong một, vì vậy bạn có thể nhập schema OpenAPI của API DRF của mình, gửi các yêu cầu trực tiếp đến một máy chủ đang chạy và xây dựng các khẳng định một cách trực quan mà không cần viết thêm Python. DRF có thể tạo ra một schema OpenAPI, và Apidog trực tiếp tiêu thụ nó, điều này giữ cho client của bạn đồng bộ với hợp đồng thực tế. Bạn cũng có thể xây dựng các kịch bản kiểm thử nhiều bước, ví dụ: đăng nhập, tạo một bài viết, tìm nạp nó, xóa nó và chạy chúng theo lịch trình hoặc trong CI. Điều này bổ sung cho bộ APITestCase của bạn chứ không thay thế nó: các bài kiểm thử đơn vị và endpoint bảo vệ mã, client API bảo vệ dịch vụ đã triển khai. Bạn có thể tải xuống Apidog để nhập schema DRF và dùng thử. Đối với các nhóm thích làm việc với Python từ đầu đến cuối, hướng dẫn khung kiểm thử tự động API pytest cho thấy cách chạy các bài kiểm thử kiểu DRF dưới pytest.

Câu hỏi thường gặp

Sự khác biệt giữa TestCase và APITestCase là gì?

TestCase của Django gói mỗi bài kiểm thử trong một giao dịch cơ sở dữ liệu và cung cấp cho bạn một client kiểm thử Django tiêu chuẩn. APITestCase của DRF kế thừa từ nó và thay thế client bằng APIClient, client này hiểu các lược đồ xác thực DRF, đàm phán nội dung và đối số format trong các yêu cầu. Sử dụng APITestCase để kiểm thử các endpoint DRF.

Khi nào tôi nên sử dụng force_authenticate thay vì login?

Sử dụng force_authenticate() khi bạn muốn kiểm thử logic view và quyền hạn mà không tốn chi phí và sự phức tạp của luồng thông tin đăng nhập thực tế. Nó gắn trực tiếp một người dùng vào yêu cầu. Sử dụng login() hoặc credentials() khi cơ chế xác thực, chẳng hạn như session hoặc token auth, là điều bạn muốn xác minh.

Các bài kiểm thử DRF có cần một máy chủ đang chạy không?

Không. APIClient gửi các yêu cầu trong tiến trình trực tiếp đến các view của bạn, vì vậy bộ kiểm thử chạy mà không cần khởi động máy chủ. Đó là điều làm cho nó nhanh chóng. Để kiểm thử dịch vụ thực sự đã triển khai, bao gồm cả cơ sở hạ tầng như proxy và CORS, bạn gửi các yêu cầu HTTP thực tế bằng một API client như Apidog.

Làm cách nào để kiểm tra độ bao phủ kiểm thử cho một dự án DRF?

Cài đặt gói coverage, sau đó chạy coverage run --source='.' manage.py test, tiếp theo là coverage report để có bản tóm tắt hoặc coverage html để xem từng dòng. Báo cáo HTML làm nổi bật các dòng chưa được kiểm thử để bạn có thể thấy chính xác những view hoặc serializer nào thiếu kiểm thử.

Tôi có nên kiểm thử serializers và endpoint riêng biệt không?

Có. Các bài kiểm thử đơn vị serializer nhanh chóng và xác định lỗi xác thực mà không tốn chi phí HTTP. Các bài kiểm thử endpoint với APITestCase kiểm tra định tuyến, quyền hạn và chu trình yêu cầu đầy đủ. Việc giữ cả hai mang lại cho bạn phản hồi nhanh ở cấp độ đơn vị và sự tự tin rằng các kết nối hoạt động ở cấp độ tích hợp.

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API

Kiểm Tra API Django REST Framework: Hướng Dẫn Chi Tiết