Kỹ thuật lập trình và xử lý kịch bản BeanShell trong JMeter

Các biến tích hợp sẵn trong BeanShell

Trong JMeter, BeanShell cung cấp một tập hợp các biến mặc định cho phép tương tác trực tiếp với ngữ cảnh thực thi. Dưới đây là các biến quan trọng và cách ứng dụng:

  • log: Ghi thông tin gỡ lỗi vào file jmeter.log hoặc hiển thị trên console.
  • vars: Đối tượng JMeterVariables, dùng để thao tác với các biến cục bộ trong phạm vi Thread Group (get, put).
  • props: Đối tượng JMeterProperties, thao tác với các thuộc tính toàn cục, có thể chia sẻ giữa nhiều Thread Group.
  • ctx: Đại diện cho JMeterContext, cung cấp quyền truy cập vào thông tin luồng hiện tại, request và response.
  • prev: Tham chiếu đến SampleResult của request ngay trước đó, dùng để trích xuất dữ liệu phản hồi.

Ngoài ra, bạn có thể truy cập các thuộc tính của SampleResult thông qua prev như:

  • prev.getResponseDataAsString(): Lấy nội dung body của response dưới dạng chuỗi.
  • prev.getResponseCode(): Lấy mã trạng thái HTTP (ví dụ: 200).
  • prev.getResponseHeaders(): Lấy toàn bộ header của response.
  • prev.setSuccessful(boolean) hoặc Failure: Thiết lập trạng thái thành công hay thất bại của sample.

Sử dụng BeanShell Sampler để tạo dữ liệu động

BeanShell Sampler thường được dùng để sinh dữ liệu phức tạp mà các hàm có sẵn của JMeter không đáp ứng được. Ví dụ, tạo mã định danh ngẫu nhiên và lưu vào biến.

Sự khác biệt cốt lõi giữa varsprops là phạm vi hoạt động: vars chỉ tồn tại trong một Thread Group, trong khi props có giá trị trên toàn bộ Test Plan.

Xử lý Response với BeanShell PostProcessor

Khi cần phân tích cú pháp hoặc biến đổi dữ liệu trả về, BeanShell PostProcessor là lựa chọn tối ưu. Thông qua biến prev (tương đương ctx.getPreviousResult()), ta có thể đọc và xử lý response trước khi chuyển sang bước tiếp theo.

Các kịch bản mẫu và tối ưu hóa mã nguồn

1. Sinh mã định danh ngẫu nhiên không chứa ký tự đặc biệt

import java.util.UUID;

// Tạo UUID và loại bỏ dấu gạch ngang
String rawUuid = UUID.randomUUID().toString();
String formattedId = rawUuid.replace("-", "").toUpperCase();

// Lưu vào biến JMeter để sử dụng ở các request sau
vars.put("generated_transaction_id", formattedId);
log.info("New Transaction ID: " + formattedId);

2. Ghép chuỗi tham số từ danh sách biến động

Giả sử bạn cần gom nhiều ID từ một Regular Expression Extractor thành một chuỗi JSON array.

int matchCount = Integer.parseInt(vars.get("user_ids_matchNr"));
StringBuilder jsonPayload = new StringBuilder("[");

if (matchCount > 0) {
    for (int i = 1; i <= matchCount; i++) {
        String currentId = vars.get("user_ids_" + i);
        jsonPayload.append("{\"userId\":\"").append(currentId).append("\",\"status\":\"active\"}");
        if (i < matchCount) {
            jsonPayload.append(",");
        }
    }
}
jsonPayload.append("]");

vars.put("final_user_payload", jsonPayload.toString());

3. Ghi dữ liệu trích xuất ra file CSV

import java.io.BufferedWriter;
import java.io.FileWriter;

int recordCount = Integer.parseInt(vars.get("order_refs_matchNr"));
String filePath = "extracted_orders.csv";

if (recordCount > 0) {
    // Sử dụng try-with-resources để tự động đóng stream
    try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) {
        for (int i = 1; i <= recordCount; i++) {
            String orderRef = vars.get("order_refs_" + i);
            writer.write(orderRef + "\n");
        }
    } catch (Exception e) {
        log.error("Error writing to file: " + e.getMessage());
    }
}

4. Tích hợp thư viện JAR tùy chỉnh

Đặt file JAR vào thư mục jmeter/lib và khởi tạo lớp mã hóa.

import com.mycompany.crypto.AESEncryptor;

AESEncryptor encryptor = new AESEncryptor();
String secretKey = "MySecretKey12345";
String rawData = vars.get("sensitive_payload");

String encryptedData = encryptor.encrypt(rawData, secretKey);
vars.put("encrypted_payload", encryptedData);

5. Tùy chỉnh Assertion (BeanShell Assertion)

Đoạn mã dưới đây kiểm tra xem response có chứa mã lỗi cụ thể hay không. Lưu ý: Chỉ sử dụng trong BeanShell Assertion.

String responseBody = prev.getResponseDataAsString();
String expectedToken = "\"errorCode\":\"SUCCESS\"";

if (responseBody != null && responseBody.contains(expectedToken)) {
    Failure = false; // Đánh dấu sample thành công
} else {
    Failure = true;  // Đánh dấu sample thất bại
    FailureMessage = "Validation failed. Expected token not found in response.";
    log.error(FailureMessage + " | Actual response: " + responseBody);
}

6. Định dạng thời gian tùy chỉnh

import java.text.SimpleDateFormat;
import java.util.Calendar;

Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH, 1); // Lấy ngày mai

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
String futureDate = formatter.format(cal.getTime());

vars.put("tomorrow_timestamp", futureDate);

7. Chia sẻ dữ liệu giữa các Thread Group

Để truyền token từ luồng đăng ký sang luồng thực thi nghiệp vụ, sử dụng hàm __setProperty__P.

Thread Group 1 (Lưu biến toàn cục):

${__setProperty(global_auth_token,${login_token},)}

Thread Group 2 (Đọc biến toàn cục):

${__P(global_auth_token,)}

8. Xử lý ký tự xuống dòng trong Regular Expression

Khi dữ liệu response chứa ký tự xuống dòng làm hỏng việc bắt chuỗi, hãy dùng hàm escape:

${__unescape(\n)}

9. Tham số hóa số lượng Thread và thời gian chạy

Sử dụng thuộc tính hệ thống để điều khiển cấu hình từ dòng lệnh (CLI).

Threads: ${__P(concurrent_users,10)}
Duration: ${__P(test_duration,60)}

10. Mã hóa và giải mã Base64

Sử dụng các hàm có sẵn của JMeter Custom Functions hoặc Plugins:

Mã hóa:

${__base64Encode({"action":"verify"\,"token":"abc123"},encoded_request)}

Giải mã:

${__base64Decode(YWN0aW9uOnZlcmlmeQ==,decoded_response)}

Thẻ: jmeter beanshell performance-testing Java api-testing

Đăng vào ngày 22 tháng 9 lúc 11:48