Các lớp học và phương pháp kiểm tra

Đã hoàn thành

Ngoài việc viết các chức năng kiểm tra, Pytest cho phép bạn sử dụng các lớp học. Như chúng tôi đã đề cập, không cần thừa kế và các lớp kiểm tra tuân theo một vài quy tắc đơn giản. Việc sử dụng lớp học sẽ giúp bạn linh hoạt hơn và có thể tái sử dụng. Như bạn thấy tiếp theo, Pytest giữ ra khỏi con đường và tránh buộc bạn phải viết bài kiểm tra một cách nhất định.

Cũng giống như các hàm, bạn vẫn có thể viết hiển thị bằng cách sử dụng assert lệnh.

Xây dựng lớp kiểm tra

Hãy sử dụng một kịch bản trong thế giới thực để xem các lớp kiểm tra có thể giúp ích như thế nào. Hàm sau đây kiểm tra xem tệp đã cho có chứa nội dung "có" hay không. Nếu vậy, nó trả về giá True. Nếu tệp không tồn tại hoặc nếu tệp chứa "không" trong nội dung của nó, nó trả về giá False. Kịch bản này phổ biến trong các tác vụ không đồng bộ sử dụng hệ thống tệp để cho biết hoàn thành.

Dưới đây là diện mạo của hàm:

import os

def is_done(path):
    if not os.path.exists(path):
        return False
    with open(path) as _f:
        contents = _f.read()
    if "yes" in contents.lower():
        return True
    elif "no" in contents.lower():
        return False

Bây giờ, đây là cách một lớp học với hai bài kiểm tra (một cho mỗi điều kiện) trong một tệp có tên test_files.py ra:

class TestIsDone:

    def test_yes(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("yes")
        assert is_done("/tmp/test_file") is True

    def test_no(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("no")
        assert is_done("/tmp/test_file") is False

Thận trọng

Các phương pháp kiểm tra sử dụng đường dẫn /tmp cho tệp kiểm tra tạm thời vì sẽ dễ sử dụng hơn cho ví dụ. Tuy nhiên, nếu bạn cần sử dụng các tệp tạm thời, hãy cân nhắc sử dụng thư viện như tempfile có thể tạo (và xóa) chúng một cách an toàn cho bạn. Không phải mọi hệ thống đều có thư mục /tmp và vị trí đó có thể không phải là tạm thời tùy thuộc vào hệ điều hành.

Chạy các kiểm tra với cờ -v để tăng mức độ chi tiết cho thấy các kiểm tra đi qua:

pytest -v test_files.py
============================= test session starts ==============================
Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 
cachedir: .pytest_cache
rootdir: /private/
collected 2 items

test_files.py::TestIsDone::test_yes PASSED                               [ 50%]
test_files.py::TestIsDone::test_no PASSED                                [100%]

============================== 2 passed in 0.00s ===============================

Mặc dù các kiểm tra đang đi qua, chúng trông lặp đi lặp lại và chúng cũng rời khỏi các tệp sau khi kiểm tra xong. Trước khi chúng ta thấy chúng ta có thể cải thiện chúng như thế nào, hãy nói về các phương pháp trợ giúp trong phần tiếp theo.

Phương pháp của người trợ giúp

Trong lớp kiểm tra, có một vài phương pháp bạn có thể sử dụng để thiết lập và xé bỏ thực thi kiểm tra. Pytest sẽ tự động thực thi chúng nếu chúng được xác định. Để sử dụng các phương pháp này, bạn nên biết rằng chúng có một thứ tự và hành vi cụ thể.

  • setup: Thực hiện một lần trước mỗi kiểm tra trong một lớp.
  • teardown: Thực hiện một lần sau mỗi kiểm tra trong một lớp.
  • setup_class: Thực hiện một lần trước tất cả các kiểm tra trong một lớp.
  • teardown_class: Thực hiện một lần sau tất cả các kiểm tra trong một lớp.

Khi kiểm tra yêu cầu các tài nguyên tương tự (hoặc giống hệt nhau) hoạt động, sẽ rất hữu ích nếu viết các phương pháp thiết lập. Tốt nhất, kiểm tra không nên để lại tài nguyên khi hoàn thành, vì vậy các phương pháp xé xuống có thể giúp trong việc dọn dẹp kiểm tra trong những tình huống đó.

Dọn dẹp

Chúng ta hãy xem một lớp kiểm tra cập nhật giúp dọn sạch các tệp sau mỗi lần kiểm tra:

class TestIsDone:

    def teardown(self):
        if os.path.exists("/tmp/test_file"):
            os.remove("/tmp/test_file")

    def test_yes(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("yes")
        assert is_done("/tmp/test_file") is True

    def test_no(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("no")
        assert is_done("/tmp/test_file") is False

Vì chúng tôi đã sử teardown() phương pháp này, lớp kiểm tra này không còn để lại /tmp/test_file lại.

Thiết lập

Một cải tiến khác mà chúng tôi có thể thực hiện cho lớp này là thêm một biến trỏ đến tệp. Vì tệp hiện được khai báo ở sáu vị trí, mọi thay đổi đối với đường dẫn sẽ có nghĩa là thay đổi nó trong tất cả các vị trí đó. Ví dụ này cho thấy diện mạo của lớp với phương pháp setup() khai báo biến đường dẫn:

class TestIsDone:

    def setup(self):
        self.tmp_file = "/tmp/test_file"

    def teardown(self):
        if os.path.exists(self.tmp_file):
            os.remove(self.tmp_file)

    def test_yes(self):
        with open(self.tmp_file, "w") as _f:
            _f.write("yes")
        assert is_done(self.tmp_file) is True

    def test_no(self):
        with open(self.tmp_file, "w") as _f:
            _f.write("no")
        assert is_done(self.tmp_file) is False

Các phương pháp trợ giúp tùy chỉnh

Bạn có thể tạo các phương pháp trợ giúp tùy chỉnh trong một lớp học. Các phương pháp này không được tiền tố với tên test và không thể được đặt tên là phương pháp thiết lập hoặc dọn dẹp. Trong lớp học TestIsDone , chúng tôi có thể tự động hóa việc tạo tệp tạm thời trong trình trợ giúp tùy chỉnh. Phương pháp trợ giúp tùy chỉnh đó có thể trông giống như ví dụ sau:

    def write_tmp_file(self, content):
        with open(self.tmp_file, "w") as _f:
            _f.write(content)

Pytest không tự động thực thi phương pháp write_tmp_file() và các phương pháp khác có thể gọi trực tiếp phương pháp này để lưu vào các tác vụ lặp lại như viết vào tệp.

Toàn bộ lớp sẽ trông giống như ví dụ này, sau khi cập nhật các phương pháp kiểm tra để sử dụng trình trợ giúp tùy chỉnh:

class TestIsDone:

    def setup(self):
        self.tmp_file = "/tmp/test_file"

    def teardown(self):
        if os.path.exists(self.tmp_file):
            os.remove(self.tmp_file)

    def write_tmp_file(self, content):
        with open(self.tmp_file, "w") as _f:
            _f.write(content)

    def test_yes(self):
        self.write_tmp_file("yes")
        assert is_done(self.tmp_file) is True

    def test_no(self):
        self.write_tmp_file("no")
        assert is_done(self.tmp_file) is False

Khi nào nên sử dụng lớp thay vì hàm

Không có bất kỳ quy tắc nghiêm ngặt nào về thời điểm sử dụng lớp thay vì hàm. Bạn nên theo dõi các quy ước trong các dự án và nhóm hiện tại mà bạn đang làm việc cùng. Dưới đây là một số câu hỏi chung cần đặt ra mà có thể giúp các em xác định khi nào nên sử dụng lớp học:

  • Các kiểm tra của bạn có cần thiết lập hoặc dọn dẹp mã người trợ giúp tương tự không?
  • Việc nhóm các kiểm tra của bạn lại với nhau có ý nghĩa hợp lý không?
  • Có ít nhất một vài kiểm tra trong bộ kiểm tra của bạn không?
  • Các kiểm tra của bạn có thể được hưởng lợi từ một tập hợp các hàm trợ giúp phổ biến không?