Tại sao kiểm thử tự động trên di động cần Model Context Protocol

06 tháng 4, 2026·10 phút đọc

Bài viết phân tích những điểm yếu của các khung kiểm thử UI hiện tại và giới thiệu Model Context Protocol (MCP) cùng công cụ Drengr để giải quyết vấn đề. Cách tiếp cận mới này cho phép LLM điều khiển thiết bị trực tiếp thông qua JSON-RPC, giảm thiểu sự phụ thuộc vào bộ chọn (selector) dễ vỡ và tăng cường khả năng hiểu ngữ cảnh cho quá trình kiểm thử.

Tại sao kiểm thử tự động trên di động cần Model Context Protocol

Tại sao kiểm thử tự động trên di động cần Model Context Protocol

Sau một thập kỷ viết các bài kiểm thử UI cho Android liên tục bị hỏng trong mỗi sprint, tôi đã ngừng hỏi làm thế nào để làm cho các bộ chọn (selectors) bền vững hơn. Thay vào đó, tôi bắt đầu tự hỏi tại sao chúng ta lại phải phụ thuộc vào những selector mong manh như vậy.

Hầu hết các framework hiện nay đều cào (scrape) cấu trúc phân cấp view, sau đó tạo ra các chuỗi XPath hoặc resource-id. Những chuỗi này rất dễ vỡ ngay khi UI được tái cấu trúc (refactor). Ngay khi nhà thiết kế thay đổi một TextView thành một Button có cùng nhãn, bài kiểm thử sẽ sập ngay lập tức.

Việc thiết lập cũng là một "hố đen" khác. Bạn phải khởi động server Appium, trỏ nó đến một cloud farm, cung cấp driver tương thích với Selenium, sau đó vật lộn với các khả năng (capabilities) không khớp nhau. Toàn bộ ngăn xếp công nghệ này liên tục biến động.

Và khi thiết bị finally làm điều gì đó bất ngờ — một hộp thoại của hệ điều hành, hết giờ mạng, hay bị crash — hầu hết các công cụ chỉ ném ra một ngoại lệ và dừng lại. Không có ngữ cảnh, không có khôi phục, không có thông tin chi tiết.

Tôi đã xây dựng Drengr vì tôi mệt mỏi với việc coi thiết bị như một DOM từ xa. Tôi muốn một mô hình mà LLM có thể suy luận, không phải là một chuỗi selector dễ vỡ.

Một cách tiếp cận khác: trao cho AI một thiết bị thực

Đó chính là lúc Model Context Protocol (MCP) xuất hiện. Đây là một tệp nhị phân Rust dung lượng 5MB chạy trên máy trạm của bạn, giao tiếp với thiết bị qua ADB (đối với Android) hoặc trình mô phỏng iOS, và expose giao diện JSON-RPC 2.0 trên stdio. Không có HTTP server, không có cổng phụ, chỉ là một đường ống sạch sẽ.

# start the MCP server
drengr mcp

Máy chủ này duy trì trạng thái hoạt động, lắng nghe các lệnh gọi phương thức như drengr_do, drengr_querydrengr_look. Mỗi lệnh gọi trả về một báo cáo tình huống: một blob JSON nhỏ cho bạn biết màn hình có thay đổi không, phần tử nào xuất hiện hay biến mất, activity có chuyển đổi không, và thiết bị có bị kẹt hay crash không.

Vì phương thức truyền tải là stdio, bất kỳ ngôn ngữ nào có thể tạo ra quy trình con (child process) đều có thể trở thành máy khách. Claude Desktop, Cursor, tiện ích mở rộng VS Code — bất cứ thứ gì hiểu JSON-RPC giờ đây đều có thể điều khiển một chiếc điện thoại thực.

Cách Drengr giao tiếp với thiết bị

Ba công cụ tạo nên giao thức

Công cụChức năngVí dụ
drengr_lookChụp màn hình, chạy OCR, trả về JPEG có chú thích (hoặc mô tả văn bản ~300 token)drengr_look{"elements":[{"id":1,"label":"Login"}]}
drengr_doThực hiện một trong 13 hành động (chạm, gõ, vuốt, ...) trên cả AndroidiOS{"method":"drengr_do","params":{"action":"tap","element":1}}
drengr_queryKéo logs, dump UI, lưu lượng mạng, trạng thái ứng dụng, v.v.drengr_query {"method":"logcat","params":{}}

Cả ba đều chia sẻ cùng một bao bọc (envelope) JSON-RPC, vì vậy bạn có thể xâu chuỗi chúng trong một vòng lặp máy khách duy nhất. Dưới đây là một lệnh "chạm vào nút đầu tiên" tối thiểu:

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "drengr_do",
  "params": {
    "action": "tap",
    "element": 1
  }
}

Phản hồi sẽ trông như thế này:

{
  "jsonrpc": "2.0",
  "id": 42,
  "result": {
    "screen_changed": true,
    "new_elements": [{"id": 2, "label": "Welcome"}],
    "disappeared_elements": [{"id": 1}],
    "activity_changed": false,
    "crash": false,
    "stuck": false
  }
}

Payload nhỏ đó rẻ để gửi qua mạng, rẻ để lưu trữ và rẻ cho bất kỳ LLM nào để tiêu hóa. Nó hoàn toàn đối lập với việc gửi một tệp PNG 1-MB cho mỗi bước.

Chế độ chỉ văn bản (Text-only) so với chuyển đổi thị giác (Vision escalation)

Nếu OCR có thể trích xuất văn bản cho ít nhất 60% các phần tử hiển thị, Drengr sẽ giữ nguyên chế độ chỉ văn bản. Điều này tương đương với khoảng 300 token mỗi màn hình, chỉ tốn một phần nhỏ xu cho mỗi lần chạy kiểm thử khi bạn tính phí sử dụng LLM.

Khi độ phủ văn bản giảm xuống dưới ngưỡng này, máy chủ sẽ quay lại using JPEG với các lớp phủ được đánh số. LLM sau đó sẽ thấy bản đồ trực quan và vẫn có thể suy luận về bố cục. Đây là sự suy giảm tự nhiên (graceful degradation), không phải là một chuyển đổi cứng nhắc.

Tổng hợp: một bộ kiểm thử đơn giản

Sức mạnh thực sự được thể hiện khi bạn để một LLM điều khiển MCP. Drengr đi kèm với một định dạng YAML nhỏ đọc giống như một danh sách kiểm tra. Không cần mã hóa, không cần driver Selenium, chỉ có ý định.

app: com.example.app
tasks:
  - name: login
    task: "Đăng nhập với [email protected] và password123"
    timeout: 60s
  - name: search
    task: "Tìm kiếm tai nghe và thêm kết quả đầu tiên vào giỏ hàng"
    timeout: 90s

Chạy nó bằng một lệnh duy nhất:

drengr test tests.yml --output json

CLI sẽ khởi tạo MCP, truyền phát các báo cáo tình huống đến LLM bạn đã cấu hình với drengr key set, và in ra một mảng JSON kết quả của các bước. Bạn cũng có thể yêu cầu định dạng JUnit XML để tích hợp CI.

Phía dưới, trình chạy kiểm thử sẽ thực hiện các bước sau:

  1. drengr_look → lấy mô tả cảnh.
  2. Gửi prompt cho LLM: "Làm thế nào để hoàn thành nhiệm vụ với cảnh này?"
  3. Phân tích phản hồi của LLM thành một chuỗi các lệnh drengr_do.
  4. Sau mỗi hành động, gọi drengr_query để lấy ui_dumplogcat nhằm phát hiện crash hoặc frame bị kẹt.
  5. Lặp lại cho đến khi hết giờ chờ nhiệm vụ hoặc thành công.

Tất cả những điều này được phối hợp bởi vài trăm dòng Rust trong tệp nhị phân MCP và một trình bao bọc Python mỏng xử lý API LLM. Công việc nặng nề vẫn nằm trên thiết bị, không phải trên một lưới Selenium từ xa.

Điều gì hoạt động, điều gì không

Những điểm tích cực

  • Không còn sự mong manh của selector. LLM hoạt động với các nhãn có thể đọc được của con người ("Login", "Add to cart"). Nếu UI đổi một Button thành ComposeView, mô hình vẫn thấy token văn bản giống nhau.
  • Phản hồi nhanh. Chế độ chỉ văn bản có nghĩa là thời gian khứ hồi khoảng 30ms trên thiết bị cục bộ, so với vài giây để tải ảnh lên và OCR trên dịch vụ đám mây.
  • Phát hiện trạng thái kẹt được tích hợp sẵn. Năm khung hình giống hệt nhau sẽ kích hoạt cờ stuck:true, nhắc LLM tự động quay lại.
  • Tương đồng đa nền tảng. Cùng một JSON drengr_do hoạt động trên trình mô phỏng Android và iOS. Không cần script Appium riêng biệt.

Những đánh đổi

  • Không có endpoint HTTP. Một số pipeline CI mong đợi máy chủ REST. Bạn phải bọc quy trình stdio hoặc sử dụng drengr doctor được cung cấp để xác minh tình trạng sức khỏe.
  • Vision fallback vẫn nặng nề về JPEG. Khi OCR thất bại, bạn phải trả giá cho một ảnh chụp màn hình và LLM phải phân tích các lớp phủ được đánh số. Việc chuyển đổi hiện tại hoạt động nhưng chưa tinh tế.
  • Độ trễ LLM là yếu tố bên ngoài. Ngay cả khi sử dụng Gemini làm mặc định, một yêu cầu lạnh có thể mất 1–2 giây, chiếm chủ yếu thời gian cho mỗi hành động trên một thiết bị nhanh.
  • Telemetry hạn chế. Các báo cáo tình huống được thiết kế ngắn gọn. Nếu bạn cần các sự kiện ứng dụng tùy chỉnh, bạn phải mở rộng MCP hoặc đo lường ứng dụng của chính mình.

Tôi thành thật: MVP hoạt động cho vòng lặp chính (nhìn → quyết định → hành động). Các trường hợp cạnh — hộp thoại phương thức chặn OCR, ứng dụng Android nhiều cửa sổ, chế độ chia nhỏ trên iOS — vẫn cần được hoàn thiện.

Hướng đi của hệ sinh thái

Các xu hướng tôi thấy phù hợp với ba mục tiêu trong lộ trình của chúng tôi.

  1. Trích xuất văn bản trên thiết bị – Đưa OCR vào tệp nhị phân MCP để chúng ta có thể giữ chế độ chỉ văn bản ngay cả khi hệ điều hành vẽ đè lên UI (ví dụ: hộp thoại hệ thống). Điều này sẽ loại bỏ hoàn toàn việc sử dụng JPEG dự phòng.
  2. Hooks telemetry SDK phong phú hơn – Hiện tại báo cáo tình huống cho bạn biết cái gì đã thay đổi, không phải tại sao. Việc thêm các sự kiện tùy chỉnh từ ứng dụng (ví dụ: "user_logged_in") sẽ cho phép LLM đưa ra các quyết định cấp cao hơn mà không cần đoán.
  3. Lập hoạch có nhận thức về đồ thị (Graph-aware planning)drengr explore đã xây dựng một đồ thị điều hướng dưới ~/.drengr/maps/. Bước tiếp theo là expose đồ thị này cho LLM để nó có thể tính toán đường đi ngắn nhất đến màn hình đích thay vì lang thang mù quáng.

Những bước đi này phù hợp với các chuyển dịch rộng hơn của ngành: nhiều AI hơn trên thiết bị, tích hợp chặt chẽ hơn giữa các framework kiểm thử và telemetry ứng dụng, và sự thúc đẩy hướng tới điều hướng dựa trên mô hình thay vì ghi và phát lại (record-and-replay).

Những điều tôi vẫn đang tìm hiểu

Tôi vẫn đang vật lộn với hai câu hỏi mở:

  • Làm thế nào để khiến việc nhắc LLM mang tính xác định đủ cho CI. Hiện tại, mô hình có thể tạo ra các chuỗi hành động khác nhau cho cùng một cảnh, điều này ổn để kiểm thử khám phá nhưng gây nhiễu cho các bộ kiểm thử hồi quy. Tôi đang thử nghiệm với các khuôn mẫu few-shot và kiểm soát nhiệt độ, nhưng điểm ngọt ngào (sweet spot) vẫn khó nắm bắt.
  • Phối hợp đa thiết bị. Drengr có thể kết nối với cả Android và iOS cùng lúc, chuyển đổi bằng tham số device. Thách thức tiếp theo là điều phối một LLM duy nhất để vừa xử lý cả hai thiết bị trong một kịch bản duy nhất — hãy nghĩ đến "cài đặt trên Android, xác minh trên iOS". Giao thức hỗ trợ điều này, nhưng logic lập hoạch cần được viết lại.

Nếu bạn tò mò, hãy khởi động một thiết bị, chạy drengr mcp, và bắn một lệnh drengr_do nhanh từ REPL yêu thích của bạn. Bạn sẽ thấy cùng payload JSON nhỏ mà tôi đã trình bày ở trên. Từ đó, bạn có thể bắt đầu đưa nó vào Claude, GPT-4 hoặc Anthropic và xem LLM bắt đầu "nói chuyện" với điện thoại của bạn.

Kiểm thử tự động trên di động sẽ không trở thành "không có framework" trong một sớm một chiều, nhưng việc trao cho AI cái nhìn cụ thể, độ trễ thấp về thiết bị là một bước tiến tới các bài kiểm thực sự hiểu ứng dụng, không phải chỉ là một ảnh chụp tĩnh DOM. Đó là xu hướng mà tôi đang đặt cược vào.

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗