2012-11-21 36 views
10

tôi đang làm việc trên một con trăn chương trình Command-Line-Interface, và tôi thấy nó nhàm chán khi làm xét nghiệm, ví dụ, đây là thông tin trợ giúp của chương trình:Python CLI đơn vị chương trình thử nghiệm

usage: pyconv [-h] [-f ENCODING] [-t ENCODING] [-o file_path] file_path 

Convert text file from one encoding to another. 

positional arguments: 
    file_path 

optional arguments: 
    -h, --help   show this help message and exit 
    -f ENCODING, --from ENCODING 
         Encoding of source file 
    -t ENCODING, --to ENCODING 
         Encoding you want 
    -o file_path, --output file_path 
         Output file path 

Khi Tôi đã thay đổi chương trình và muốn kiểm tra điều gì đó, tôi phải mở một terminal, nhập lệnh (với các tùy chọn và đối số), nhập enter và xem có lỗi nào xảy ra trong khi đang chạy hay không. Nếu lỗi thực sự xảy ra, tôi phải quay lại trình chỉnh sửa và kiểm tra mã từ đầu đến cuối, đoán vị trí lỗi, thực hiện các thay đổi nhỏ, viết print đường, quay lại thiết bị đầu cuối, chạy lại lệnh ...

đệ quy. Vì vậy, câu hỏi của tôi là, cách tốt nhất để làm thử nghiệm với chương trình CLI là gì, có thể dễ dàng thử nghiệm đơn vị với các tập lệnh python bình thường không?

Trả lời

3

Câu trả lời ngắn gọn là có, bạn có thể sử dụng các bài kiểm tra đơn vị, và nên. Nếu mã của bạn được cấu trúc tốt, nó sẽ khá dễ dàng để kiểm tra từng thành phần riêng biệt, và nếu bạn cần phải luôn luôn có thể thử sys.argv để mô phỏng chạy nó với các đối số khác nhau.

0

Điều này không dành riêng cho Python, nhưng những gì tôi làm để kiểm tra tập lệnh dòng lệnh là chạy chúng với các đầu vào và tùy chọn được xác định trước khác nhau và lưu đầu ra chính xác trong tệp. Sau đó, để kiểm tra chúng khi tôi thực hiện thay đổi, tôi chỉ cần chạy tập lệnh mới và đưa đầu ra vào diff correct_output -. Nếu các tập tin giống nhau, nó sẽ không có kết quả gì. Nếu chúng khác nhau, nó sẽ cho bạn thấy ở đâu. Điều này sẽ chỉ hoạt động nếu bạn đang sử dụng Linux hoặc OS X; trên Windows, bạn sẽ phải nhận được MSYS.

Ví dụ:

python mycliprogram --someoption "some input" | diff correct_output -

Để làm cho nó thậm chí còn dễ dàng hơn, bạn có thể thêm tất cả các thử nghiệm chạy để 'làm test' Makefile mục tiêu của bạn, mà tôi giả sử bạn đã có. ;)

Nếu bạn đang chạy nhiều trong số này cùng một lúc, bạn có thể làm cho nó một ít rõ ràng hơn trong đó mỗi một kết thúc bằng cách thêm thẻ thất bại:

python mycliprogram --someoption "some input" | diff correct_output - || tput setaf 1 && echo "FAILED"

1

Vì vậy, câu hỏi của tôi là, cách tốt nhất để làm thử nghiệm với chương trình CLI là gì, nó có thể dễ dàng như thử nghiệm đơn vị với các tập lệnh python bình thường không?

Sự khác biệt duy nhất là khi bạn chạy mô-đun Python làm tập lệnh, thuộc tính __name__ được đặt thành '__main__'. Vì vậy, nói chung, nếu bạn có ý định chạy tập lệnh của mình từ dòng lệnh, biểu mẫu phải có dạng sau:

import sys 

# function and class definitions, etc. 
# ... 
def foo(arg): 
    pass 

def main(): 
    """Entry point to the script""" 

    # Do parsing of command line arguments and other stuff here. And then 
    # make calls to whatever functions and classes that are defined in your 
    # module. For example: 
    foo(sys.argv[1]) 


if __name__ == '__main__': 
    main() 

Bây giờ không có sự khác biệt, cách bạn sử dụng: script hoặc mô-đun. Vì vậy, bên trong mã thử nghiệm đơn vị của bạn, bạn chỉ có thể nhập chức năng foo, gọi nó và thực hiện bất kỳ xác nhận nào bạn muốn.

-1

Bạn có thể sử dụng mô-đun unittest tiêu chuẩn:

# python -m unittest <test module> 

hoặc sử dụng nose như một khuôn khổ thử nghiệm.Chỉ cần viết các tệp chưa được chia sẻ cổ điển trong thư mục riêng biệt và chạy:

# nosetests <test modules directory> 

Viết unittests thật dễ dàng. Chỉ cần thực hiện theo online manual for unittesting

1

Tôi sẽ không kiểm tra toàn bộ chương trình này không phải là chiến lược thử nghiệm tốt và có thể không thực sự nắm bắt được vị trí thực sự của lỗi. Giao diện CLI chỉ là giao diện người dùng đối với một API. Bạn kiểm tra API thông qua các bài kiểm tra đơn vị của bạn và sau đó khi bạn thực hiện một thay đổi cho một phần cụ thể bạn có một trường hợp thử nghiệm để thực hiện thay đổi đó.

Vì vậy, hãy cấu trúc lại ứng dụng của bạn để bạn kiểm tra API chứ không phải ứng dụng đó. Tuy nhiên, bạn có thể có một bài kiểm tra chức năng thực sự chạy ứng dụng đầy đủ và kiểm tra xem đầu ra có đúng không.

Tóm lại, có kiểm tra mã giống như kiểm tra bất kỳ mã nào khác, nhưng bạn phải kiểm tra từng phần thay vì kết hợp của chúng để đảm bảo rằng các thay đổi của bạn không làm hỏng mọi thứ.

6

Tôi nghĩ rằng việc kiểm tra chức năng ở mức toàn bộ chương trình là hoàn toàn tốt đẹp. Bạn vẫn có thể thử nghiệm một khía cạnh/tùy chọn cho mỗi thử nghiệm. Bằng cách này bạn có thể chắc chắn rằng chương trình thực sự hoạt động như một toàn thể. Viết đơn vị-kiểm tra thường có nghĩa là bạn có thể thực hiện các bài kiểm tra của bạn nhanh hơn và thất bại thường dễ dàng hơn để giải thích/hiểu. Nhưng các bài kiểm tra đơn vị thường gắn liền với cấu trúc chương trình, đòi hỏi nhiều nỗ lực tái cấu trúc hơn khi bạn thay đổi nội bộ mọi thứ.

Dù sao, sử dụng py.test, đây là một ví dụ nhỏ để thử nghiệm một latin1 để chuyển đổi utf8 cho pyconv ::

# content of test_pyconv.py 

import pytest 

# we reuse a bit of pytest's own testing machinery, this should eventually come 
# from a separatedly installable pytest-cli plugin. 
pytest_plugins = ["pytester"] 

@pytest.fixture 
def run(testdir): 
    def do_run(*args): 
     args = ["pyconv"] + list(args) 
     return testdir._run(*args) 
    return do_run 

def test_pyconv_latin1_to_utf8(tmpdir, run): 
    input = tmpdir.join("example.txt") 
    content = unicode("\xc3\xa4\xc3\xb6", "latin1") 
    with input.open("wb") as f: 
     f.write(content.encode("latin1")) 
    output = tmpdir.join("example.txt.utf8") 
    result = run("-flatin1", "-tutf8", input, "-o", output) 
    assert result.ret == 0 
    with output.open("rb") as f: 
     newcontent = f.read() 
    assert content.encode("utf8") == newcontent 

Sau khi cài đặt pytest ("PIP cài đặt pytest"), bạn có thể chạy nó như thế này ::

$ py.test test_pyconv.py 
=========================== test session starts ============================ 
platform linux2 -- Python 2.7.3 -- pytest-2.4.5dev1 
collected 1 items 

test_pyconv.py . 

========================= 1 passed in 0.40 seconds ========================= 

Ví dụ sử dụng lại một số máy móc nội bộ của thử nghiệm riêng của pytest bằng cách tận dụng cơ chế cố định của pytest, xem http://pytest.org/latest/fixture.html. Nếu bạn quên thông tin chi tiết trong giây lát, bạn có thể làm việc với thực tế là "chạy" và "tmpdir" được cung cấp để giúp bạn chuẩn bị và chạy thử nghiệm. Nếu bạn muốn chơi, bạn có thể thử chèn một câu lệnh khẳng định không thành công hoặc chỉ đơn giản là "khẳng định 0" và sau đó xem xét truy nguyên hoặc phát hành "py.test --pdb" để nhập dấu nhắc python.

+0

Có thể sử dụng stdin và stdin với lịch thi đấu 'chạy' không? –