PYTHON UNIT TESTING
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.

Sử dụng Mock trong Unittest của Python

Không phải lúc nào mình cũng có thể kiểm tra mã nguồn một cách trực tiếp, đặc biệt khi mã nguồn phụ thuộc vào các yếu tố bên ngoài như hệ thống, mạng, hoặc các I/O operation. Để giải quyết vấn đề này, Python cung cấp mô-đun unittest.mock với lớp Mock, giúp mình mô phỏng các đối tượng thực tế và kiểm tra mã nguồn một cách độc lập và hiệu quả hơn. Trong bài viết này, mình sẽ tìm hiểu về lớp Mock của unittest.mock, cách sử dụng nó để mô phỏng các đối tượng khác, và lợi ích của việc sử dụng Mock trong việc kiểm tra mã nguồn Python.

test php

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Giới thiệu về lớp Mock của unittest trong Python

Mocks mô phỏng hành vi của các đối tượng thực tế. Để kiểm tra một đối tượng phụ thuộc vào các đối tượng khác một cách độc lập, bạn sử dụng các đối tượng mock để mô phỏng các đối tượng thực.

Để mô phỏng các đối tượng, bạn sử dụng mô-đun unittest.mock. Mô-đun này cung cấp lớp Mock cho phép bạn mô phỏng các đối tượng khác. Nó cũng cung cấp lớp MagicMock, là một lớp con của Mock. Ngoài các phương thức và thuộc tính của lớp Mock, lớp MagicMock còn có các triển khai của tất cả các phương thức đặc biệt như __str____repr__.

Xem ví dụ sau:

Bài viết này được đăng tại [free tuts .net]

from unittest.mock import Mock

# tạo một đối tượng mock mới
mock = Mock()

# mô phỏng hàm api
mock.api.return_value = {
    'id': 1,
    'message': 'hello'
}
# gọi hàm api
print(mock.api())

Kết quả:

{'id': 1, 'message': 'hello'}

Cách hoạt động:

Đầu tiên, import lớp Mock từ mô-đun unittest.mock:

from unittest.mock import Mock

Thứ hai, tạo một thể hiện mới của lớp Mock:

mock = Mock()

Thứ ba, mô phỏng hàm api() và gán giá trị trả về của nó là một từ điển:

mock.api.return_value = {
    'id': 1,
    'message': 'hello'
}

Cuối cùng, gọi hàm api() từ đối tượng mock. Nó sẽ trả về giá trị đã gán:

print(mock.api())

Trong ví dụ này, mình có hai đối tượng mock: mockmock.api.

Thêm câu lệnh print() vào chương trình để xem cách nó hoạt động:

from unittest.mock import Mock

# tạo một đối tượng mock mới
mock = Mock()
print(mock)

# mô phỏng hàm api
mock.api.return_value = {
    'id': 1,
    'message': 'hello'
}
print(mock.api)

# gọi hàm api
print(mock.api())

Kết quả:

<Mock id='1830094470496'>
<Mock name='mock.api' id='1830100086416'>
{'id': 1, 'message': 'hello'}

Kết quả cho thấy hai đối tượng Mock.

Tóm lại, nếu bạn gán một thuộc tính không tồn tại trên đối tượng Mock, Python sẽ trả về một đối tượng mock mới. Nhờ vào tính năng này, bạn có thể sử dụng lớp Mock để mô phỏng bất kỳ đối tượng nào bạn muốn.

Khi nào sử dụng mock của unittest trong Python

Đây là những trường hợp bạn nên xem xét sử dụng mock:

  • Các lệnh gọi hệ thống
  • Mạng
  • Hoạt động I/O
  • Đồng hồ & thời gian, múi giờ
  • Hoặc các trường hợp khác mà kết quả không thể dự đoán trước

Tại sao sử dụng mock của unittest trong Python

Lợi ích của mock bao gồm:

  • Tăng tốc độ kiểm tra
  • Loại trừ các yếu tố dư thừa bên ngoài
  • Làm cho các kết quả không thể đoán trước trở nên có thể đoán trước

Ví dụ về sử dụng Mock trong Python Unittest

Giả sử bạn có một mô-đun gọi là odometer.py:

from random import randint

def speed():
    return randint(40, 120)

def alert():
    s = speed()
    if s < 60 or s > 100:
        return True
    return False

Trong mô-đun sensor.py:

  • Hàm speed() trả về tốc độ hiện tại của một phương tiện. Nó trả về một giá trị ngẫu nhiên giữa 40 và 120. Trong thế giới thực, hàm này sẽ đọc dữ liệu từ đồng hồ đo tốc độ.
  • Hàm alert() trả về True nếu tốc độ hiện tại thấp hơn 60 km/h và cao hơn 100 km/h. Hàm alert() sử dụng hàm speed() để lấy tốc độ hiện tại.

Screenshot 202024 06 17 20162333 png

Sẽ rất khó kiểm tra hàm alert() vì giá trị trả về bởi hàm speed() là khác nhau. Để giải quyết, bạn có thể sử dụng lớp Mock.

Sau đây là cách tạo mô-đun kiểm tra test_odometer.py để kiểm tra hàm alert():

import unittest
from unittest.mock import Mock
import odometer

class TestOdometer(unittest.TestCase):
    def test_alert_normal(self):
        odometer.speed = Mock()
        odometer.speed.return_value = 70
        self.assertFalse(odometer.alert())

    def test_alert_overspeed(self):
        odometer.speed = Mock()
        odometer.speed.return_value = 100
        self.assertFalse(odometer.alert())

    def test_alert_underspeed(self):
        odometer.speed = Mock()
        odometer.speed.return_value = 59
        self.assertTrue(odometer.alert())

Chạy kiểm tra:

Screenshot 202024 06 17 20162347 png

python -m unittest test_odometer.py -v

Kết quả:

test_alert_normal (test_odometer.TestOdometer) ... ok
test_alert_overspeed (test_odometer.TestOdometer) ... ok
test_alert_underspeed (test_odometer.TestOdometer) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

Kết bài

Việc sử dụng lớp Mock của mô-đun unittest.mock trong Python giúp bạn dễ dàng mô phỏng các đối tượng khác để kiểm tra mã nguồn một cách độc lập và hiệu quả. Nhờ vào các tính năng mạnh mẽ của lớp Mock, bạn có thể loại bỏ các yếu tố không thể đoán trước và tăng tốc độ kiểm tra. Hy vọng rằng qua bài viết này, bạn đã hiểu rõ hơn về cách sử dụng mock để nâng cao chất lượng và độ tin cậy của mã nguồn Python.

Cùng chuyên mục:

Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python

Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python

Hướng dẫn toàn diện về module datetime trong Python

Hướng dẫn toàn diện về module datetime trong Python

Cách truy cập và thiết lập biến môi trường trong Python

Cách truy cập và thiết lập biến môi trường trong Python

Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass

Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass

Từ khóa yield trong Python

Từ khóa yield trong Python

Sự khác biệt giữa sort() và sorted() trong Python

Sự khác biệt giữa sort() và sorted() trong Python

Sử dụng Poetry để quản lý dependencies trong Python

Sử dụng Poetry để quản lý dependencies trong Python

Định dạng chuỗi Strings trong Python

Định dạng chuỗi Strings trong Python

Một tác vụ phổ biến khi làm việc với danh sách trong Python

Một tác vụ phổ biến khi làm việc với danh sách trong Python

Làm việc với các biến môi trường trong Python

Làm việc với các biến môi trường trong Python

Sự khác biệt giữa set() và frozenset() trong Python

Sự khác biệt giữa set() và frozenset() trong Python

Sự khác biệt giữa iterator và iterable trong Python

Sự khác biệt giữa iterator và iterable trong Python

Cách làm việc với file tarball/tar trong Python

Cách làm việc với file tarball/tar trong Python

Chuyển đổi kiểu dữ liệu trong Python

Chuyển đổi kiểu dữ liệu trong Python

Sự khác biệt giữa toán tử == và is trong Python

Sự khác biệt giữa toán tử == và is trong Python

Làm việc với file ZIP trong Python

Làm việc với file ZIP trong Python

Cách sử dụng ThreadPoolExecutor trong Python

Cách sử dụng ThreadPoolExecutor trong Python

Sự khác biệt giữa byte objects và string trong Python

Sự khác biệt giữa byte objects và string trong Python

Xử lý độ chính xác các hàm floor, ceil, round, trunc, format  trong Python

Xử lý độ chính xác các hàm floor, ceil, round, trunc, format trong Python

Cách lặp qua nhiều list với hàm zip() trong Python

Cách lặp qua nhiều list với hàm zip() trong Python

Top