目次  
- 1 1. Python unittest là gì?
- 2 2. Cách sử dụng cơ bản của unittest
- 3 3. Cách sử dụng setUp() và tearDown()
- 4 4. Kiểm thử các phụ thuộc bằng mock
- 5 5. Xử lý ngoại lệ và assertion tùy chỉnh
- 6 6. Tính năng phát hiện kiểm thử của unittest
- 7 7. Mẹo nâng cao hiệu năng khi dùng unittest
- 8 8. Tổng kết và các bước tiếp theo
1. Python unittest là gì?
unittest là một framework kiểm thử đơn vị thuộc thư viện chuẩn của Python và là một công cụ quan trọng để đảm bảo chất lượng mã. Nó cho phép các nhà phát triển kiểm thử riêng lẻ từng phần của mã và giúp phát hiện lỗi sớm. Ngoài ra, trong quá trình phát triển liên tục, nó giúp xác nhận rằng các thay đổi trong mã không làm hỏng các chức năng hiện có。Tầm quan trọng của kiểm thử đơn vị
Khi mã trở nên phức tạp hơn, việc xác minh liệu các phần khác nhau có phối hợp hoạt động đúng hay không trở nên khó khăn. Bằng cách áp dụng kiểm thử đơn vị, bạn sẽ dễ dàng ngăn chặn các lỗi bất ngờ do những thay đổi nhỏ gây ra và duy trì sự ổn định tổng thể của chương trình。2. Cách sử dụng cơ bản của unittest
Cơ bản củaunittest là tạo một lớp kế thừa unittest.TestCase và định nghĩa các phương thức kiểm thử trong đó. Trong phương thức kiểm thử, sử dụng các phương thức assertion như assertEqual() để so sánh kết quả mong đợi với kết quả thực tế。Ví dụ kiểm thử cơ bản
Đoạn mã sau là một ví dụ đơn giản để kiểm thử hàmadd(a, b)。import unittest
# Mã cần kiểm thử
def add(a, b):
    return a + b
# Lớp kiểm thử
class TestAddFunction(unittest.TestCase):
    def test_add_integers(self):
        result = add(2, 3)
        self.assertEqual(result, 5)
if __name__ == '__main__':
    unittest.main()add() có hoạt động đúng hay không. Phương thức assertEqual() xác nhận rằng giá trị mong đợi và kết quả thực tế là bằng nhau. Bằng cách này, bạn có thể xác nhận rằng hàm hoạt động đúng trên nhiều trường hợp khác nhau.Mở rộng kiểm thử
Bạn có thể sử dụng nhiều phương thức kiểm thử để kiểm tra hành vi của hàm với các đầu vào khác nhau. Ví dụ, cũng có thể kiểm thử số dấu phẩy động và phép nối chuỗi.def test_add_floats(self):
    result = add(2.5, 3.5)
    self.assertAlmostEqual(result, 6.0, places=2)
def test_add_strings(self):
    result = add("Hello, ", "World!")
    self.assertEqual(result, "Hello, World!")
3. Cách sử dụng setUp() và tearDown()
Để tự động thực thi các xử lý cụ thể trước và sau khi kiểm thử, hãy sử dụng các phương thứcsetUp() và tearDown(). Nhờ đó, bạn có thể chuẩn bị những thứ cần thiết trước khi chạy bài kiểm thử và thực hiện dọn dẹp sau khi kiểm thử kết thúc.Ví dụ về setUp()
setUp() là phương thức luôn được gọi trước khi mỗi phương thức kiểm thử được thực thi, cho phép gom các thao tác khởi tạo dùng chung.def setUp(self):
    self.temp_value = 42Ví dụ về tearDown()
tearDown() là phương thức được thực thi sau mỗi phương thức kiểm thử, thực hiện hậu xử lý và giải phóng tài nguyên. Chẳng hạn, có thể dùng để ngắt kết nối cơ sở dữ liệu hoặc xóa các tệp tạm.def tearDown(self):
    self.temp_value = None4. Kiểm thử các phụ thuộc bằng mock
Khi mã cần kiểm thử phụ thuộc vào tài nguyên bên ngoài (cơ sở dữ liệu, API, v.v.), việc thay thế các phần phụ thuộc đó bằng mock giúp cải thiện tốc độ thực thi kiểm thử và cho phép các bài kiểm thử có tính dự đoán. Sử dụng mô-đununittest.mock của Python sẽ giúp thực hiện điều này một cách đơn giản.Ví dụ về mock
Trong đoạn mã dưới đây, chúng ta thay thế hàm tốn nhiều thời giantime_consuming_function() bằng mock.from unittest.mock import patch
class TestAddFunction(unittest.TestCase):
    @patch('my_module.time_consuming_function')
    def test_add_with_mock(self, mock_func):
        mock_func.return_value = 0
        result = add(2, 3)
        self.assertEqual(result, 5)time_consuming_function bằng cách sử dụng mock. Nhờ đó, thời gian kiểm thử được rút ngắn trong khi vẫn thu được kết quả chính xác.
5. Xử lý ngoại lệ và assertion tùy chỉnh
unittest cho phép bạn kiểm thử cả việc xử lý ngoại lệ. Ví dụ, để xác nhận rằng ngoại lệ phát sinh đúng trong những tình huống nhất định, hãy dùng assertRaises()。Kiểm thử xử lý ngoại lệ
Ví dụ sau xác nhận rằngZeroDivisionError sẽ phát sinh。def test_divide_by_zero(self):
    with self.assertRaises(ZeroDivisionError):
        divide(1, 0)divide(1, 0) thì sẽ phát sinh ZeroDivisionError。Tạo assertion tùy chỉnh
Trong các trường hợp mà các assertion tiêu chuẩn không đáp ứng được, bạn có thể tạo phương thức assertion tùy chỉnh của riêng mình。def assertIsPositive(self, value):
    self.assertTrue(value > 0, f'{value} is not positive')6. Tính năng phát hiện kiểm thử của unittest
unittest có tính năng phát hiện kiểm thử cho phép tự động tìm và chạy tất cả các tệp kiểm thử trong dự án. Tính năng này đặc biệt hữu ích đối với các dự án lớn.Cách sử dụng tính năng phát hiện kiểm thử
Để chạy tính năng phát hiện kiểm thử, hãy dùng lệnh sau.python -m unittest discovertest_*.py trong thư mục được chỉ định. Nếu muốn chỉ định tệp hoặc thư mục, hãy dùng các tùy chọn như sau.python -m unittest discover -s tests -p "test_*.py"7. Mẹo nâng cao hiệu năng khi dùng unittest
Khi tốc độ thực thi kiểm thử chậm, hiệu quả phát triển sẽ giảm. Ở đây, chúng tôi giới thiệu một vài mẹo để cải thiện hiệu năng của các bài kiểm thử dùngunittest。Tối ưu hóa I/O tệp
Các bài kiểm thử cần đọc/ghi tệp có thể tăng tốc bằng cách xử lý trong bộ nhớ. Bằng cách sử dụngStringIO để tạo một đối tượng hoạt động như một tệp ngay trên bộ nhớ, bạn có thể tránh I/O đĩa。from io import StringIO
class TestFileOperations(unittest.TestCase):
    def test_write_to_memory(self):
        output = StringIO()
        output.write('Hello, World!')
        self.assertEqual(output.getvalue(), 'Hello, World!')Sử dụng mock
Để giảm thiểu việc truy cập tài nguyên bên ngoài, bạn có thể dùng mock để tăng tốc kiểm thử. Nhờ đó, có thể tránh độ trễ từ mạng, cơ sở dữ liệu, v.v. và rút ngắn thời gian chạy kiểm thử. Trong ví dụ sau, các lời gọi API được thay thế bằng mock。from unittest.mock import MagicMock
class TestApiCall(unittest.TestCase):
    def test_api_response(self):
        mock_api = MagicMock(return_value={'status': 'success'})
        response = mock_api()
        self.assertEqual(response['status'], 'success')8. Tổng kết và các bước tiếp theo
Trong bài viết này, chúng tôi đã trình bày toàn diện từ những kiến thức cơ bản về kiểm thử đơn vị bằngunittest của Python, cách sử dụng setup và teardown, kiểm thử các phụ thuộc bằng mock, cho đến các kỹ thuật giúp cải thiện hiệu năng kiểm thử.Tóm tắt các điểm chính
- Cách sử dụng cơ bản: Kế thừa unittest.TestCasevà tận dụng các phương thức assertion để tạo bài kiểm thử.
- setUp() / tearDown(): Gom và quản lý các xử lý chung trước và sau mỗi bài kiểm thử để cải thiện khả năng tái sử dụng và tính dễ đọc của mã.
- Sử dụng mock: Có thể kiểm thử chức năng mà không phụ thuộc vào tài nguyên bên ngoài, nhờ đó hiệu quả kiểm thử được cải thiện đáng kể.
- Test discovery: Tính năng hữu ích giúp đơn giản hóa việc quản lý kiểm thử trong các dự án lớn.
- Các kỹ thuật cải thiện hiệu năng: Nhờ xử lý trong bộ nhớ và sử dụng mock, có thể rút ngắn thời gian chạy kiểm thử.
Các bước tiếp theo
Sau khi nắm vững những điều cơ bản củaunittest, hãy thử các phương pháp kiểm thử nâng cao hơn. Chẳng hạn, bạn có thể tăng cường chiến lược kiểm thử cho toàn bộ dự án bằng kiểm thử tham số hóa (cho phép kiểm thử nhiều dữ liệu đầu vào cùng lúc) và dùng công cụ coverage để kiểm tra phạm vi kiểm thử của mã. Ngoài ra, cũng nên cân nhắc các framework kiểm thử khác như pytest để mở rộng lựa chọn phù hợp với nhu cầu.  Kiểm thử là một yếu tố quan trọng trong phát triển. Hãy chủ động áp dụng kiểm thử để phát hiện lỗi sớm và duy trì chất lượng mã.
 
 


