Thể dục

Đã hoàn thành

Trong bài tập này, bạn sử dụng Pytest để kiểm tra một hàm. Sau đó, bạn tìm và khắc phục một số sự cố tiềm ẩn với hàm gây ra kiểm tra lỗi. Xem xét các lỗi và sử dụng báo cáo lỗi phong phú của Pytest là điều cần thiết để xác định và khắc phục các kiểm tra hoặc lỗi có vấn đề trong mã sản xuất.

Đối với bài tập này, chúng ta sử dụng một hàm được gọi là admin_command() chấp nhận lệnh hệ thống làm đầu vào và tùy chọn đặt tiền tố bằng công cụ sudo hệ thống. Hàm này có một lỗi mà bạn khám phá bằng cách viết bài kiểm tra.

Bước 1 - Thêm một tệp với các bài kiểm tra cho bài tập này

  1. Sử dụng quy ước tên tệp của Python cho các tệp thử nghiệm, tạo một tệp thử nghiệm mới. Đặt tên cho tệp test_exercise.py và thêm mã sau:

    def admin_command(command, sudo=True):
        """
        Prefix a command with `sudo` unless it is explicitly not needed. Expects
        `command` to be a list.
        """
        if sudo:
            ["sudo"] + command
        return command
    

    Hàm admin_command() danh sách dưới dạng dữ liệu nhập bằng cách dùng đối số command và tùy chọn có thể đặt tiền tố cho danh sách bằng sudo. Nếu tham đối từ sudo được đặt thành False, thì nó trả về cùng một lệnh được cung cấp với input.

  2. Trong cùng một tệp, chắp thêm các kiểm tra cho hàm admin_command() này. Các kiểm tra sử dụng một phương pháp trợ giúp trả về một lệnh mẫu:

    class TestAdminCommand:
    
    def command(self):
        return ["ps", "aux"]
    
    def test_no_sudo(self):
        result = admin_command(self.command(), sudo=False)
        assert result == self.command()
    
    def test_sudo(self):
        result = admin_command(self.command(), sudo=True)
        expected = ["sudo"] + self.command()
        assert result == expected
    

Ghi

Không phổ biến khi có các kiểm tra trong cùng một tệp với mã thực tế. Để đơn giản, các ví dụ trong bài tập này có mã thực tế trong cùng một tập tin. Trong các dự án Python trong thế giới thực, các thử nghiệm thường được phân tách bởi các tệp và thư mục từ mã mà chúng đang thử nghiệm.

Bước 2 - Chạy các kiểm tra và xác định sự cố

Bây giờ, tệp thử nghiệm đã có một hàm để kiểm tra và một vài kiểm tra để xác minh hành vi của nó, đã đến lúc chạy các bài kiểm tra và làm việc với lỗi.

  • Thực hiện tệp với Python:

    $ pytest test_exercise.py
    

    Quá trình chạy sẽ hoàn tất khi một kiểm tra đi qua và một lần thất bại và đầu ra lỗi phải tương tự như đầu ra sau đây:

    =================================== FAILURES ===================================
    __________________________ TestAdminCommand.test_sudo __________________________
    
    self = <test_exercise.TestAdminCommand object at 0x10634c2e0>
    
        def test_sudo(self):
            result = admin_command(self.command(), sudo=True)
            expected = ["sudo"] + self.command()
    >       assert result == expected
    E       AssertionError: assert ['ps', 'aux'] == ['sudo', 'ps', 'aux']
    E         At index 0 diff: 'ps' != 'sudo'
    E         Right contains one more item: 'aux'
    E         Use -v to get the full diff
    
    test_exercise.py:24: AssertionError
    =========================== short test summary info ============================
    FAILED test_exercise.py::TestAdminCommand::test_sudo - AssertionError: assert...
    ========================= 1 failed, 1 passed in 0.04s ==========================
    

    Đầu ra không thành công trên kiểm test_sudo() thử nghiệm. Pytest đang cung cấp thông tin chi tiết về hai danh sách đang được so sánh. Trong trường hợp này, result biến số không có lệnh sudo trong đó, đó là điều mà kiểm tra mong đợi.

Bước 3 - Sửa lỗi và làm cho các bài kiểm tra vượt qua

Trước khi thực hiện bất kỳ thay đổi nào, bạn phải hiểu tại sao có một sự thất bại ngay từ đầu. Mặc dù bạn có thể thấy rằng sự mong đợi không được đáp ứng (sudo không phải là kết quả), bạn phải tìm hiểu lý do tại sao.

Hãy xem các dòng mã sau đây từ hàm admin_command() khi điều kiện sudo=True được đáp ứng:

    if sudo:
        ["sudo"] + command

Thao tác của danh sách không được dùng để trả về giá trị. Vì nó không được trả về, hàm sẽ trả về lệnh mà không sudo luôn.

  1. Cập nhật hàm admin_command() để trả về thao tác danh sách sao cho kết quả đã sửa đổi được sử dụng khi yêu sudo lệnh. Hàm được cập nhật sẽ có dạng như sau:

    def admin_command(command, sudo=True):
        """
        Prefix a command with `sudo` unless it is explicitly not needed. Expects
        `command` to be a list.
        """
        if sudo:
            return ["sudo"] + command
        return command
    
  2. Chạy lại kiểm tra với Pytest. Hãy thử tăng mức độ chi tiết của đầu ra bằng cách sử -v với Pytest:

    $ pytest -v test_exercise.py
    
  3. Bây giờ hãy xác minh đầu ra. Nó sẽ hiển thị hai bài kiểm tra qua bây giờ:

    ============================= 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_exercise.py::TestAdminCommand::test_no_sudo PASSED                  [ 50%]
    test_exercise.py::TestAdminCommand::test_sudo PASSED                     [100%]
    
    ============================== 2 passed in 0.00s ===============================
    

Ghi

Vì hàm có thể làm việc với nhiều giá trị hơn của vỏ khác nhau, nên thêm nhiều kiểm tra để bao gồm các biến thể đó. Điều này sẽ ngăn các thay đổi trong tương lai đối với hàm gây ra hành vi khác (không mong muốn).

Bước 4 - Thêm mã mới với các kiểm tra

Sau khi thêm kiểm tra trong các bước trước đó, bạn sẽ cảm thấy thoải mái khi thực hiện nhiều thay đổi hơn đối với chức năng và xác minh chúng bằng các kiểm tra. Ngay cả khi các thay đổi không được bảo hiểm bởi các bài kiểm tra hiện có, bạn có thể cảm thấy tự tin rằng bạn không phá vỡ bất kỳ giả định trước đó.

Trong trường hợp này, hàm admin_command() tin một cách mù quáng rằng đối số command luôn là một danh sách. Hãy cải thiện điều đó bằng cách đảm bảo rằng một ngoại lệ với thông báo lỗi hữu ích được nêu ra.

  1. Trước tiên, tạo một thử nghiệm chụp hành vi. Mặc dù hàm chưa được cập nhật, hãy thử một phương pháp thử nghiệm đầu tiên (còn được gọi là Test Driven Development hoặc TDD).

    • Cập nhật test_exercise.py tệp mới để tệp pytest nhập ở trên cùng. Kiểm tra này sử dụng người trợ giúp nội bộ từ pytest framework:
    import pytest
    
    • Bây giờ chắp thêm một bài kiểm tra mới cho lớp học để kiểm tra ngoại lệ. Kiểm tra này dự kiến một TypeError từ hàm khi giá trị được chuyển cho nó không phải là danh sách:
        def test_non_list_commands(self):
            with pytest.raises(TypeError):
                admin_command("some command", sudo=True)
    
  2. Chạy lại các bài kiểm tra với Pytest. Họ nên tất cả vượt qua:

    ============================= test session starts ==============================
    Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: /private/
    collected 3 items
    
    test_exercise.py ...                                                     [100%]
    
    ============================== 3 passed in 0.00s ===============================
    

    Việc kiểm tra là đủ tốt để kiểm tra TypeError nhưng sẽ là tốt để thêm mã với một thông báo lỗi hữu ích.

  3. Cập nhật hàm để nâng cao hiệu TypeError rõ ràng với thông báo lỗi hữu ích:

    def admin_command(command, sudo=True):
        """
        Prefix a command with `sudo` unless it is explicitly not needed. Expects
        `command` to be a list.
        """
        if not isinstance(command, list):
            raise TypeError(f"was expecting command to be a list, but got a {type(command)}")
        if sudo:
            return ["sudo"] + command
        return command
    
  4. Cuối cùng, cập nhật test_non_list_commands() pháp để kiểm tra thông báo lỗi:

    def test_non_list_commands(self):
        with pytest.raises(TypeError) as error:
            admin_command("some command", sudo=True)
        assert error.value.args[0] == "was expecting command to be a list, but got a <class 'str'>"
    

    Kiểm tra cập nhật sử error làm biến chứa tất cả thông tin ngoại lệ. Sử error.value.args, bạn có thể xem các đối số của ngoại lệ. Trong trường hợp này, tham đối đầu tiên có chuỗi lỗi mà kiểm tra có thể kiểm tra.

Kiểm tra công việc của bạn

Tại thời điểm này, bạn nên có một tệp thử nghiệm Python có tên test_exercise.py bao gồm:

  • Hàm admin_command() chấp nhận một đối số và một đối số từ khóa.
  • Ngoại TypeError với thông báo lỗi hữu ích trong hàm admin_command() này.
  • Một lớp TestAdminCommand() kiểm tra có một phương pháp trợ command() và ba phương pháp kiểm tra giúp kiểm tra admin_command() năng.

Tất cả các xét nghiệm nên vượt qua mà không có lỗi khi bạn chạy chúng trong thiết bị đầu cuối.