Hướng dẫn python mutation testing pytest - thử nghiệm đột biến của trăn pytest
Nội phân Chính showShow Show
Mutmut là một hệ thống thử nghiệm đột biến cho Python, tập trung mạnh vào việc dễ sử dụng. Nếu bạn không biết thử nghiệm đột biến nào là hãy thử bắt đầu với bài viết này. Một số tính năng nổi bật:
Nếu bạn cần chạy Mutmut trên cơ sở mã Python 2, hãy sử dụng Mutmut [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct4. Mutmut [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct5 là phiên bản cuối cùng hỗ trợ Python [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct6, [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct7 và [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct8. Cài đặt và chạyBạn có thể bắt đầu với một đơn giản: pip install mutmut mutmut run Điều này theo mặc định sẽ chạy pytest (hoặc không nhất định nếu pytest không có sẵn) trong các bài kiểm tra trong thư mục thử nghiệm của các thử nghiệm hoặc hoặc thử nghiệm và nó sẽ cố gắng tìm ra mã để biến đổi ở đâu. Chạy Đối với các cờ có sẵn, để sử dụng các vận động viên khác, v.v ... Cách được đề xuất để sử dụng Mutmut nếu mặc định không có hoạt động cho bạn là thêm một khối trong [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct9. Sau đó, khi bạn quay lại Mutmut vài tuần sau đó, bạn không phải tìm ra cờ một lần nữa, chỉ cần chạy [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/0 và nó hoạt động. Như thế này: [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct Để sử dụng nhiều đường dẫn trong tùy chọn [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/1 hoặc [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/2, hãy sử dụng danh sách phân tách dấu phẩy hoặc đại tràng. Ví dụ: [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/ Bạn có thể dừng đột biến chạy bất cứ lúc nào và Mutmut sẽ khởi động lại nơi bạn rời đi. Nó cũng đủ thông minh để chỉ kiểm tra lại các đột biến còn sống khi bộ thử nghiệm thay đổi. Để in kết quả chạy [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/3. Nó sẽ cung cấp cho bạn một danh sách các đột biến được nhóm theo tệp. Bây giờ bạn có thể xem xét một đột biến cụ thể khác với [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/4, tất cả các đột biến cho một tệp cụ thể với [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/5 hoặc tất cả các đột biến với [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/6. Bạn cũng có thể viết một đột biến cho đĩa với [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/7. Bạn thực sự nên có tập tin bạn đột biến trong kiểm soát mã nguồn và cam kết trước khi bạn áp dụng một đột biến!REALLY have the file you mutate under source code control and committed before you apply a mutant! Danh sách trắngBạn có thể đánh dấu các dòng như thế này: some_code_here() # pragma: no mutate để dừng đột biến trên những dòng đó. Một số trường hợp chúng tôi đã tìm thấy nơi bạn cần để danh sách trắng là:
Xem thêm Cấu hình và danh sách trắng nâng cao Ví dụ đột biến
Nói chung, ý tưởng là các đột biến nên tinh tế nhất có thể. Xem some_code_here() # pragma: no mutate0 để biết danh sách đầy đủ. Quy trình làm việcPhần này mô tả cách làm việc với Mutmut để tăng cường bộ thử nghiệm của bạn.
Mutmut giữ một bộ đệm kết quả trong some_code_here() # pragma: no mutate5, vì vậy nếu bạn muốn đảm bảo rằng bạn chạy một cuộc chạy Mutmut đầy đủ, chỉ cần xóa tệp này. Nếu bạn muốn chạy lại tất cả những người sống sót sau khi thay đổi nhiều mã hoặc thậm chí cấu hình, bạn có thể sử dụng cho ID trong $ (ID kết quả Mutmut còn tồn tại); làm Mutmut chạy $ id; thực hiện (cho bash). Bạn cũng có thể nói với Mutmut chỉ cần kiểm tra một đột biến duy nhất: Cấu hình và danh sách trắng tiên tiếnMutmut có một hệ thống cấu hình tiên tiến. Bạn tạo một tệp gọi là some_code_here() # pragma: no mutate6. Bạn có thể xác định hai chức năng ở đó: some_code_here() # pragma: no mutate7 và some_code_here() # pragma: no mutate8. some_code_here() # pragma: no mutate9 được gọi khi Mutmut bắt đầu và def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else0 được gọi trước khi mỗi đột biến được áp dụng và thử nghiệm. Bạn có thể biến đổi đối tượng def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else1 khi bạn cần. Bạn có thể sửa đổi lệnh kiểm tra như thế này: def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else hoặc bỏ qua một đột biến: def pre_mutation(context): if context.filename == 'foo.py': context.skip = True hoặc bỏ qua ghi nhật ký: def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True Nhìn vào mã cho lớp def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else2 để biết những gì bạn có thể sửa đổi. Vui lòng mở một vấn đề GitHub nếu bạn cần giúp đỡ. Cũng có thể vô hiệu hóa đột biến của các loại nút cụ thể bằng cách chuyển tùy chọn def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else3. Nhiều loại có thể được chỉ định bằng cách tách chúng bằng dấu phẩy: mutmut run --disable-mutation-types=string,decorator
Ngược lại, bạn cũng chỉ có thể chỉ định chỉ chạy các đột biến cụ thể với def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else4. Lưu ý rằng def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else3 và def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else4 là độc quyền và không thể kết hợp. Chọn các bài kiểm tra để chạy côngNếu bạn có một bộ thử nghiệm lớn hoặc các bài kiểm tra dài, có thể có lợi khi thu hẹp tập hợp các bài kiểm tra để chạy cho mỗi đột biến xuống các bài kiểm tra có cơ hội giết nó. Xác định tập hợp con có liên quan của các bài kiểm tra phụ thuộc vào dự án của bạn, cấu trúc của nó và siêu dữ liệu mà bạn biết về các bài kiểm tra của bạn. def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else7 cung cấp thông tin như tệp cho bối cảnh đột biến và bảo hiểm (nếu được sử dụng với công tắc def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else8). Bạn có thể đặt def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else9 trong móc some_code_here() # pragma: no mutate8 của some_code_here() # pragma: no mutate6. def pre_mutation(context): if context.filename == 'foo.py': context.skip = True2 được thiết lập lại sau mỗi đột biến, vì vậy bạn không phải (tái) đặt nó cho mỗi đột biến. Phần này đưa ra các ví dụ để cho thấy làm thế nào điều này có thể được thực hiện cho một số trường hợp sử dụng cụ thể. Tất cả các ví dụ sử dụng trình chạy thử nghiệm mặc định ( def pre_mutation(context): if context.filename == 'foo.py': context.skip = True3). Lựa chọn dựa trên bố cục nguồn và thử nghiệmNếu vị trí của mô -đun thử nghiệm có mối tương quan nghiêm ngặt với bố cục mã nguồn của bạn, bạn chỉ cần xây dựng đường dẫn đến tệp thử nghiệm tương ứng từ def pre_mutation(context): if context.filename == 'foo.py': context.skip = True4. Giả sử bố cục của bạn theo cấu trúc sau đây trong đó tệp thử nghiệm luôn được đặt ngay bên cạnh mã sản xuất: mypackage ├── production_module.py ├── test_production_module.py └── subpackage ├── submodule.py └── test_submodule.py some_code_here() # pragma: no mutate6 của bạn trong trường hợp này sẽ như thế này: import os.path def pre_mutation(context): dirname, filename = os.path.split(context.filename) testfile = "test_" + filename context.config.test_command += ' ' + os.path.join(dirname, testfile) Lựa chọn dựa trên nhập khẩuNếu bạn có thể dựa vào cấu trúc thư mục hoặc đặt tên cho các tệp thử nghiệm, bạn có thể cho rằng các thử nghiệm có khả năng tiêu diệt đột biến được đặt trong các tệp thử nghiệm trực tiếp nhập mô -đun bị ảnh hưởng bởi người đột biến. Sử dụng mô -đun def pre_mutation(context): if context.filename == 'foo.py': context.skip = True6 của thư viện tiêu chuẩn Python, bạn có thể sử dụng móc some_code_here() # pragma: no mutate7 để xây dựng bản đồ kiểm tra tệp nhập mô -đun nào, sau đó tra cứu tất cả các tệp kiểm tra nhập mô -đun đột biến và chỉ chạy chúng: [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct0 Lựa chọn dựa trên bối cảnh bảo hiểmNếu bạn ghi lại bối cảnh bảo hiểm và sử dụng công tắc def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else8, bạn có thể truy cập dữ liệu bảo hiểm này bên trong móc some_code_here() # pragma: no mutate8 thông qua thuộc tính def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True0. Thuộc tính này là một từ điển trong mẫu def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True1. Hãy nói rằng bạn đã sử dụng tùy chọn bối cảnh động tích hợp của def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True2 bằng cách thêm phần sau vào tệp def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True3 của bạn: [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct1 def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True4 sẽ tạo bối cảnh mới cho mỗi chức năng kiểm tra mà bạn chạy ở dạng def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True5. Với def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True6, chúng ta có thể sử dụng công tắc def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True7 để kiểm tra bộ lọc phù hợp với biểu thức đã cho. [mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct2 Hãy chú ý rằng định dạng của tên ngữ cảnh khác nhau tùy thuộc vào công cụ bạn sử dụng để tạo bối cảnh. Ví dụ: plugin def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True8 sử dụng def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True9 làm dấu phân cách giữa mô -đun và chức năng kiểm tra. Hơn nữa, không phải tất cả các công cụ đều có thể chọn chính xác các bối cảnh chính xác. mutmut run --disable-mutation-types=string,decorator
0 Ví dụ là (tại thời điểm viết) không thể nhận các bài kiểm tra bên trong một lớp khi sử dụng def pre_mutation(context): line = context.current_source_line.strip() if line.startswith('log.'): context.skip = True6. Bạn sẽ phải kiểm tra cơ sở dữ liệu mutmut run --disable-mutation-types=string,decorator
2 của mình bằng cách sử dụng API FAVEAGE.PY để xác định cách bạn có thể trích xuất thông tin chính xác để sử dụng với người chạy thử nghiệm.Làm cho mọi thứ trở nên mạnh mẽ hơnMặc dù có những nỗ lực tốt nhất của bạn trong việc chọn tập hợp con bài kiểm tra phù hợp, nhưng có thể xảy ra là người đột biến tồn tại vì bài kiểm tra có thể giết nó không được đưa vào bộ thử nghiệm. Bạn có thể nói với def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else7 để chạy lại bộ thử nghiệm đầy đủ trong trường hợp đó, để xác minh rằng đột biến này thực sự tồn tại. Bạn có thể làm như vậy bằng cách chuyển tùy chọn mutmut run --disable-mutation-types=string,decorator
4 cho [mutmut] paths_to_mutate=src/,src2/ tests_dir=tests/:tests2/0. Tùy chọn này được tắt theo mặc định. Hỗ trợ JUnit XMLĐể tích hợp tốt hơn với các hệ thống CI/CD, def pre_mutation(context): context.config.test_command = 'python -m pytest -x ' + something_else7 hỗ trợ việc tạo báo cáo XML JUNIT (sử dụng https://pypi.org/project/junit-xml/). Tùy chọn này có sẵn bằng cách gọi mutmut run --disable-mutation-types=string,decorator
7. Để xác định cách đối phó với các đột biến đáng ngờ và chưa được kiểm tra, bạn có thể sử dụng[mutmut] paths_to_mutate=src/ backup=False runner=python -m hammett -x tests_dir=tests/ dict_synonyms=Struct, NamedStruct3 Các giá trị có thể cho các chính sách này là:
Nếu một đột biến thất bại được đưa vào báo cáo, thì sự khác biệt thống nhất của đột biến cũng sẽ được đưa vào cho mục đích gỡ lỗi. |