PIT Mutation Testing on CI/CD Pipeline

Bài tóm tắt Trendyol 2021 2. Tăng trưởng Độ khó: Dễ

Trendyol · 2021 · 2. Tăng trưởng · Độ khó: Dễ — bài gốc

Bài nửa hướng dẫn cấu hình (Maven, GitLab CI, SonarQube); wiki chỉ giữ các quyết định về pipeline và chi phí.

Bối cảnh

  • Team Search của Trendyol (thương mại điện tử Thổ Nhĩ Kỳ) muốn tiến tới deploy một cú nhấp, nên pipeline CI/CD phải đủ tin cậy. Đang dùng code review và code coverage, nhưng coverage 100% vẫn có thể sai: test quên assert trường hợp biên, hay chạy hết code mà không assert gì.

Thay đổi chính

  • PIT (Pitest) cho Java: sửa bytecode để tạo mutant (đổi > thành >=, đảo điều kiện, bỏ gọi hàm void, trả về null/0/rỗng/true/false...), rồi chạy test; test hỏng thì mutant bị "giết", test vẫn qua thì mutant "sống" và test cần cải thiện. PIT dùng dữ liệu coverage để chỉ chạy những test có thể giết mutant đó; mutant ở dòng không được phủ thì đánh dấu sống ngay. Team dùng nhóm mutator mặc định.
  • Chỉ chạy trên code đã đổi ở mỗi nhánh feature: goal scmMutationCoverage so nhánh hiện tại với develop, chỉ đột biến class thêm mới hoặc sửa. Chạy ở bước Feature Build trong GitLab CI, đẩy kết quả sang SonarQube; mutant sống làm giảm điểm Reliability và Maintainability nên quality gate sẵn có của Sonar chặn pipeline, không cần cổng mới. Phải tạo profile Sonar mới có luật Mutation Analysis vì profile mặc định không có.
  • Chạy toàn bộ dự án chỉ khi đẩy nhánh có tên bắt đầu bằng pitest-, hoặc chạy local với -DwithHistory để lần sau nhanh hơn.
  • Chi phí: trên code đã đổi, một codebase mất 2 phút 44 giây, codebase nhỏ hơn mất 15 giây, chấp nhận được nên vẫn chạy một thread. Thêm thread nhanh hơn nhưng cần heap lớn hơn (mỗi mutant nạp trong class loader riêng); 4 thread cần heap Maven 4.096 MB, team cho là không chấp nhận được. Đặt maxDependencyDistance = 1 (chỉ chạy test gọi thẳng vào class bị đột biến) tiết kiệm đáng kể thời gian.

Vì sao

  • Mutation testing đắt vì nhân số lần chạy test theo số mutant; giới hạn vào phần code đổi trong nhánh giữ được tín hiệu cho đúng thay đổi đang review mà thời gian vẫn vừa vòng CI.

Bài học cho SWE

  • Coverage đo code có chạy qua không, không đo test có kiểm gì không; mutation testing đo phần sau.
  • Kiểm tra đắt thì chạy theo phạm vi thay đổi trên mỗi PR, còn bản đầy đủ chạy theo yêu cầu hoặc theo lịch.
  • Đưa tín hiệu mới vào cổng có sẵn (quality gate của Sonar) dễ được chấp nhận hơn dựng cổng riêng.

Liên quan