0

Hướng dẫn Setup Jenkins cho hệ thống Monolith - Bài 12: Đọc và hiển thị báo cáo kết quả Test (JUnit/TestNG Reports) trực tiếp trên giao diện Jenkins

Ở Bài 11, chúng ta đã thiết lập Jenkins tự động chạy Unit Test và xuất kết quả ra tệp reports/junit.xml. Tuy nhiên, nếu một bài test bị lỗi trong hàng nghìn test case của hệ thống Monolith, việc mở màn hình Console Output dài hàng vạn dòng chữ trắng đen để dò tìm nguyên nhân là một cực hình.

Bài học hôm nay sẽ hướng dẫn bạn biến những tệp XML khô khan đó thành biểu đồ trực quan và bảng phân tích chi tiết ngay trên giao diện của Jenkins.

1. Tại sao cần hiển thị báo cáo Test trực quan cho hệ thống Monolith?

  • Khoanh vùng lỗi tức thì (Pinpoint Failures): Thay vì cuộn trang tìm kiếm, Jenkins sẽ lọc riêng các test case bị lỗi (Failed Tests) lên đầu trang, hiển thị rõ tên Class, tên Method, thông báo lỗi (Error Message) và toàn bộ Stack Trace.

  • Theo dõi xu hướng chất lượng (Test Result Trend): Jenkins tự động vẽ biểu đồ qua từng lần build (#1, #2, #3...), giúp đội ngũ thấy rõ số lượng test case tăng lên hay giảm đi, và liệu có xuất hiện các bài test chập chờn (Flaky Tests - lúc pass lúc fail) hay không.

  • Phân biệt trạng thái Pipeline rõ ràng (SUCCESS vs UNSTABLE vs FAILURE):

    • SUCCESS (Xanh lá): Code biên dịch thành công, 100% test pass.

    • UNSTABLE (Vàng cam): Code biên dịch không lỗi, nhưng có một hoặc nhiều Unit Test bị fail.

    • FAILURE (Đỏ): Lỗi nghiêm trọng khiến quá trình chạy bị đứt gãy (ví dụ: lỗi cú pháp không biên dịch được, mất kết nối Git, sập container).

2. Cơ chế hoạt động của JUnit Plugin trong Jenkins

Mặc định khi bạn chọn Install suggested plugins ở Bài 4, Jenkins đã cài đặt sẵn JUnit Plugin.

Điểm mạnh mẽ nhất là hầu hết các ngôn ngữ lập trình hiện đại (PHPUnit, Jest, Go test, PyTest, Maven Surefire) đều hỗ trợ xuất báo cáo theo chuẩn cấu trúc XML của JUnit. Bạn chỉ cần dùng lệnh junit trong Jenkinsfile, Jenkins sẽ tự động phân tích (parse) tệp này và dựng giao diện đồ họa.

3. Tích hợp bước đọc báo cáo Test vào Jenkinsfile

Có một quy tắc sống còn khi cấu hình đọc báo cáo Test: Tuyệt đối không đặt lệnh junit nằm chung ngay sau câu lệnh chạy test trong khối steps thông thường.

Lý do: Ở Bài 11, khi có 1 test case bị fail, lệnh chạy test (phpunit, mvn test, go test) sẽ trả về mã lỗi khác 0. Jenkins sẽ lập tức dừng Stage đó lại và bỏ qua các dòng lệnh phía dưới. Hậu quả là khi test pass thì có báo cáo, còn khi test fail (lúc bạn cần xem báo cáo nhất) thì lệnh junit lại không được chạy!

Giải pháp chuẩn: Đặt lệnh junit vào bên trong khối post { always { ... } } của Stage Test hoặc của toàn bộ Pipeline.

Dưới đây là cấu hình Jenkinsfile chuẩn thực chiến:

Groovy

pipeline {
    agent any

    options {
        buildDiscarder(logRotator(numToKeepStr: '15'))
        timeout(time: 30, unit: 'MINUTES')
        timestamps()
    }

    environment {
        APP_NAME = "monolith-core-system"
        BUILD_VERSION = "v1.0.${env.BUILD_NUMBER}"
    }

    stages {
        stage('1. Checkout Source Code') {
            steps {
                checkout scm
            }
        }

        stage('2. Install Dependencies') {
            steps {
                sh 'composer install --no-interaction --prefer-dist'
            }
        }

        stage('3. Run Unit Tests') {
            environment {
                APP_ENV = "testing"
                DB_CONNECTION = "sqlite"
                DB_DATABASE = ":memory:"
            }
            steps {
                echo "=== Thực thi bộ Unit Test ==="
                sh '''
                    mkdir -p reports
                    ./vendor/bin/phpunit --log-junit reports/junit.xml
                '''
            }
            // KHỐI QUAN TRỌNG: Luôn luôn thu thập báo cáo dù Test Pass hay Fail
            post {
                always {
                    echo "=== Thu thập và phân tích báo cáo JUnit XML ==="
                    junit(
                        testResults: 'reports/junit.xml',
                        allowEmptyResults: false, // Báo lỗi ngay nếu không tìm thấy file report
                        keepLongStdio: true       // Giữ lại toàn bộ log chi tiết (stdout/stderr) của test bị lỗi
                    )
                }
            }
        }

        stage('4. Clean & Package Artifact') {
            // Chỉ đóng gói khi không có bất kỳ bài test nào bị lỗi (Trạng thái hiện tại phải là SUCCESS)
            when {
                expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' }
            }
            steps {
                echo "=== Đóng gói mã nguồn Monolith ==="
                sh '''
                    composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev
                    tar --exclude='.git' --exclude='tests' --exclude='reports' -czf ${APP_NAME}-${BUILD_VERSION}.tar.gz .
                '''
            }
        }
    }

    post {
        success {
            archiveArtifacts artifacts: "${APP_NAME}-${BUILD_VERSION}.tar.gz", fingerprint: true
        }
        unstable {
            echo "=== CẢNH BÁO: Bản build không ổn định do có Unit Test thất bại! ==="
        }
        failure {
            echo "=== LỖI HỆ THỐNG: Pipeline bị gãy giữa chừng! ==="
        }
        always {
            // Dọn dẹp báo cáo cũ để lần build sau không đọc nhầm file XML của lần trước
            sh 'rm -rf reports/ .env'
        }
    }
}

4. Giải thích các tham số nâng cao trong hàm junit

Khi cấu hình cho hệ thống Monolith lớn, bạn nên nắm rõ các tham số sau:

  • testResults: 'reports/*.xml' (hoặc 'target/surefire-reports/*.xml' với Java Maven): Hỗ trợ ký tự đại diện (wildcard *) để gom nhiều file báo cáo từ các module khác nhau trong Monolith lại thành một bảng tổng hợp duy nhất.

  • allowEmptyResults: false: Đề phòng trường hợp cấu hình sai lệnh khiến không có bài test nào chạy nhưng Pipeline vẫn báo xanh. Nếu không có file XML sinh ra, Jenkins sẽ lập tức đánh rớt bản build.

  • keepLongStdio: true: Mặc định Jenkins sẽ cắt bớt log nếu thông báo lỗi quá dài. Bật cờ này lên giúp bạn giữ nguyên toàn bộ dữ liệu JSON/SQL log in ra trong lúc debug lỗi của Monolith.

  • healthScaleFactor: 1.0: Hệ số tính điểm "Sức khỏe thời tiết" (biểu tượng Mặt trời / Đám mây / Sấm sét ngoài màn hình Dashboard).

5. Cách đọc báo cáo trực tiếp trên giao diện Jenkins Web UI

Sau khi chạy Pipeline từ 2 lần trở lên, bạn truy cập vào trang quản lý của Job (monolith-production-pipeline) sẽ thấy sự thay đổi rõ rệt:

  1. Biểu đồ Test Result Trend (Góc phải màn hình Job):

    • Hiển thị đồ thị miền theo thời gian thực. Màu xanh dương biểu thị số lượng test vượt qua (Passed), màu đỏ biểu thị số lượng test thất bại (Failed).
  2. Menu "Test Result" (Trong chi tiết từng bản Build #X):

    • Click vào bản build vừa chạy -> Chọn Test Result ở thanh menu bên trái.

    • All Failed Tests: Nếu có lỗi, danh sách các hàm bị lỗi sẽ xổ ra ngay lập tức. Bạn chỉ cần bấm vào dấu + cạnh tên hàm để xem chính xác dòng code bị sai kỳ vọng (Expected: 200, Actual: 500) kèm thời gian chạy mất bao nhiêu mili-giây.

    • All Tests: Phân nhóm gọn gàng theo từng Package / Namespace của dự án Monolith, kèm thanh đo thời gian thực thi (Duration) giúp bạn phát hiện luôn những bài test nào đang chạy quá chậm cần tối ưu.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí