Phạm Văn Thư
Phát triển và kiểm thử · Nội dung có hỗ trợ AI

Bruno: kiểm thử API bằng tệp văn bản, Git và dòng lệnh

Đăng ngày 12/10/2026

Mục lục bài nghiên cứu
Hình đại diện Bruno — công cụ lập trình và kiểm thử mã nguồn mở

Bruno trong một phút: ứng dụng gọi API lưu mọi thứ thành tệp văn bản

Bruno là một ứng dụng máy tính để khám phá và kiểm thử API. Khác với các công cụ đồng bộ qua đám mây, nó lưu bộ sưu tập (collection) thẳng vào thư mục trên ổ đĩa, mỗi yêu cầu là một tệp viết bằng ngôn ngữ đánh dấu văn bản Bru, nên đội có thể quản lý bằng Git như mã nguồn [1]. README còn cam kết Bruno chạy ngoại tuyến và không có kế hoạch thêm đồng bộ đám mây [1].

Công cụ này đáng thử khi đội kiểm thử hoặc tích hợp muốn bộ yêu cầu API được duyệt bằng pull request, chạy lại được trong CI bằng dòng lệnh bru và không muốn dữ liệu yêu cầu rời khỏi máy [1][7]. Nó ít hợp khi đội cần một nền tảng cộng tác theo thời gian thực có tài khoản và không gian làm việc chung, hoặc cần kiểm thử tải; các tệp đã đọc không mô tả hai nhu cầu đó.

Phần mềm có bản miễn phí mã nguồn mở theo giấy phép MIT và có các phiên bản trả phí; README nói đa số tính năng là miễn phí và mở, nhưng không liệt kê chính xác tính năng nào thuộc bản trả phí [1][2]. Vì vậy trước khi cam kết dùng cho cả công ty, hãy lập danh sách tính năng bạn cần rồi đối chiếu trực tiếp với trang giá của nhà cung cấp.

Vì sao một bộ sưu tập API cần sống cùng mã nguồn

Trong nhiều công ty, danh sách yêu cầu API để thử dịch vụ nằm trong một công cụ đồ họa, được chia sẻ qua tài khoản. Sau vài tháng, không ai biết phiên bản nào là đúng, ai đã sửa, vì sao tiêu đề xác thực đổi. Còn khi chuyển cùng bộ yêu cầu sang môi trường kiểm thử tự động, người ta lại viết lại bằng một công cụ khác. Đây là mô tả chung, không kèm số liệu về mức độ phổ biến.

Bruno chọn một hướng đơn giản: mỗi yêu cầu là một tệp văn bản trong thư mục, nên lịch sử, so sánh thay đổi và duyệt mã đều dùng công cụ Git quen thuộc [1]. Cùng một tệp có thể mở bằng ứng dụng đồ họa để khám phá, rồi chạy bằng bru run trong quy trình tích hợp liên tục [7]. Hai việc vốn tách rời được nối bằng một định dạng.

Cách tiếp cận này đổi lấy một điều: tính cộng tác không còn do máy chủ của nhà cung cấp trung gian, mà phụ thuộc vào kỷ luật Git của đội. Ai quen pull request sẽ thấy thuận lợi; nhóm kinh doanh hay vận hành chưa dùng Git sẽ cần được hướng dẫn thêm.

Bên trong kho mã: ứng dụng Electron và chuỗi gói theo đồ thị một chiều

Kho mã là một monorepo dùng npm workspaces. Theo tài liệu kiến trúc nội bộ, giao diện bruno-app viết bằng React với Redux Toolkit, tiến trình chính Electron nằm ở bruno-electron, trình chạy dòng lệnh ở bruno-cli, bộ chạy tập lệnh người dùng ở bruno-js, còn bruno-lang giữ ngữ pháp của ngôn ngữ Bru và bruno-filestore là nơi đọc, ghi các tệp bộ sưu tập [4]. Cần lưu ý đây là tài liệu hướng dẫn cho người đóng góp trong thư mục .claude của kho mã, nên mô tả ý định của đội phát triển hơn là một cam kết với người dùng cuối.

Điều thú vị cho người đánh giá kiến trúc là quy tắc phụ thuộc. Các gói bên trong tạo thành một đồ thị có hướng không chu trình: các gói lá như bruno-common, bruno-lang, bruno-schema không phụ thuộc gói nội bộ nào, các gói trung gian như bruno-js hay bruno-filestore dùng các gói lá, còn bruno-cli, bruno-electron và bruno-app là nơi mọi thứ đổ vào. Quy tắc cũng yêu cầu bruno-js không được phụ thuộc Electron để chạy được cả trong ứng dụng lẫn CLI, và bruno-sqlite chỉ dùng ở tiến trình chính [3].

Hệ quả thực tế: hành vi gửi yêu cầu trong CLI và trong ứng dụng đồ họa dùng chung phần lớn mã tập lệnh và đọc tệp, nên bộ kiểm thử chạy ở CI có nhiều khả năng tái hiện đúng những gì bạn thấy trên màn hình. Đây là suy luận từ cấu trúc gói, chưa kiểm chứng bằng cách chạy.

bruno — Bruno, công cụ lập trình và kiểm thử mã nguồn mở
Hình 1. Minh họa trong kho mã nguồn chính thức của Bruno. Nguồn: usebruno/bruno @8833538. Hình ảnh và nhãn hiệu thuộc về chủ sở hữu tương ứng.

Một yêu cầu đi từ ô nhập liệu đến phản hồi như thế nào

Theo mô tả quy trình thực thi, giao diện gọi tiến trình chính qua IPC của Electron với lệnh send-http-request. Biến trong yêu cầu được nội suy bằng hàm interpolate của bruno-common. Sau đó tập lệnh trước yêu cầu chạy trong ScriptRuntime của bruno-js [4].

Yêu cầu được dựng và gửi: HTTP dùng axios, ngoài ra có gRPC và WebSocket, và các khối xây dựng như bộ chặn xác thực, cookie đến từ gói bruno-requests; điều phối nằm ở tiến trình chính chứ không ở gói đó [4]. Sau khi nhận phản hồi, việc trích biến, chạy kiểm thử và chạy các khẳng định do ba runtime riêng biệt là VarsRuntime, TestRuntime và AssertRuntime đảm nhiệm, không dùng chung ScriptRuntime [4].

Kết quả trả lại giao diện dưới dạng một đối tượng dữ liệu, có trường error khi thất bại, thay vì ném ngoại lệ qua IPC [4]. Với người dùng CLI, điều này có nghĩa là lỗi mạng và lỗi kiểm thử được biểu diễn trong kết quả; bạn có thể ghi chúng ra tệp bằng tùy chọn --output [7]. Trạng thái phụ, dẫn xuất hoặc cồng kềnh được lưu trong cơ sở SQLite cục bộ bruno.db dưới thư mục dữ liệu người dùng, còn tùy chọn nhỏ nằm trong electron-store [4][9].

Những gì tài liệu xác nhận Bruno làm được

Về lưu trữ, README xác nhận bộ sưu tập là thư mục trên hệ thống tệp, thông tin yêu cầu lưu bằng ngôn ngữ Bru [1]. Tài liệu kiến trúc cho biết hiện có hai định dạng đĩa: .bru và .yml (OpenCollection YAML), bộ sưu tập mới mặc định dùng .yml, còn ngữ pháp .bru hiện hành là phiên bản 2 và phiên bản 1 là di sản [4]. Điều này đáng chú ý nếu bạn từng thấy ví dụ cũ chỉ nói về .bru.

Về loại giao thức, kiểu Request trong gói schema-types là hợp của yêu cầu HTTP, gRPC và WebSocket [4]. Về nhập xuất, gói bruno-converters được mô tả là nơi nhập, xuất từ Postman, Insomnia, OpenAPI và các định dạng khác [4], và CLI có lệnh bru import openapi tạo thư mục bộ sưu tập từ tệp hoặc URL đặc tả [7].

Về dòng lệnh, bru run chạy toàn bộ bộ sưu tập, một tệp, hoặc một thư mục; --env chọn môi trường, --output ghi kết quả, --cacert thêm chứng chỉ CA riêng và --ignore-truststore giới hạn chỉ tin CA được chỉ định [7]. Có ảnh Docker chính thức cho CLI, phát hành lên Docker Hub và GitHub Container Registry với biến thể alpine, debian cho linux/amd64 và linux/arm64 [1]. Ứng dụng đồ họa cài được qua nhiều trình quản lý gói như Homebrew, Chocolatey, Scoop, winget, Snap, Flatpak, AUR và Apt [1].

bruno — Bruno, công cụ lập trình và kiểm thử mã nguồn mở
Hình 2. Minh họa trong kho mã nguồn chính thức của Bruno. Nguồn: usebruno/bruno @8833538. Hình ảnh và nhãn hiệu thuộc về chủ sở hữu tương ứng.

Ai sẽ thấy Bruno đáng thời gian

Nhóm hưởng lợi rõ nhất là kỹ sư kiểm thử, kỹ sư tích hợp và lập trình viên backend, những người vừa cần thử API bằng tay vừa muốn tái dùng chính các yêu cầu đó trong tự động hóa. Cần biết Git ở mức cơ bản và sẵn lòng xem các thay đổi bằng cách đọc diff của tệp văn bản [1].

Nhóm thứ hai là doanh nghiệp quan tâm đến chỗ lưu dữ liệu. Vì ứng dụng ngoại tuyến và không đồng bộ đám mây theo cam kết trong README [1], nhóm bảo mật có ít điểm cần phê duyệt hơn so với công cụ phải gửi yêu cầu qua máy chủ trung gian; dù vậy vẫn phải rà soát cách lưu bí mật và đường dẫn tập lệnh như phần bảo mật bên dưới.

Nhóm ít phù hợp gồm bộ phận chỉ cần xem tài liệu API công khai, đội muốn mô phỏng dịch vụ hoặc đo tải, và tổ chức đã có một nền tảng quản lý vòng đời API riêng được đầu tư sâu. Với họ, chi phí đổi công cụ có thể lớn hơn lợi ích.

Tình huống giả định: đội tích hợp của một công ty bảo trì thang máy

Đây là một đề xuất, không phải trường hợp thực tế. Hãy hình dung một công ty bảo trì thang máy ở TP.HCM có hệ thống điều phối lệnh bảo trì, ứng dụng cho kỹ thuật viên hiện trường và cổng thông tin cho ban quản lý tòa nhà, giao tiếp với nhau qua API. Có thêm một dịch vụ nhận cảnh báo từ bộ điều khiển thang do nhà cung cấp thiết bị cung cấp. Mỗi lần nhà cung cấp thay đổi định dạng cảnh báo hay đội backend sửa API lệnh bảo trì, đội tích hợp lại phải thử tay hàng chục kịch bản.

Đề xuất là dựng một kho Git cho bộ sưu tập Bruno, chia thư mục theo nghiệp vụ: tạo lệnh bảo trì, gán kỹ thuật viên, ghi nhận kết quả kiểm tra, nhận cảnh báo sự cố. Hai môi trường staging và sản xuất được khai báo tách nhau. Một yêu cầu tạo lệnh bảo trì kèm khẳng định kiểm tra mã trạng thái và trường bắt buộc; tập lệnh sau phản hồi trích mã lệnh để yêu cầu kế tiếp dùng lại. Cơ chế biến, tập lệnh và khẳng định này phù hợp với các runtime được mô tả trong tài liệu kiến trúc [4].

Khi có pull request vào API, quy trình CI chạy bru run bằng ảnh Docker chính thức với môi trường staging và ghi kết quả ra tệp để lưu kèm bản dựng [1][7]. Nếu hệ thống đã có đặc tả OpenAPI, có thể dùng bru import openapi để tạo khung ban đầu rồi bổ sung kịch bản nghiệp vụ bằng tay [7]. Kịch bản cảnh báo sự cố chỉ nên chạy với dữ liệu giả ở staging.

Có hai điểm cần xác minh trước khi đi xa. Một là cách Bruno lưu biến bí mật như token: các tệp bài viết đã đọc không trả lời, nên cần đọc tài liệu chính thức và thử với tài khoản kiểm thử. Hai là kỹ thuật viên hiện trường không phải đối tượng dùng Bruno; họ dùng ứng dụng riêng của công ty. Bruno chỉ phục vụ đội tích hợp và kiểm thử.

Triển khai và vận hành: máy cá nhân, kho Git và một bước CI

Triển khai đơn giản: cài ứng dụng bằng trình quản lý gói phù hợp từng hệ điều hành, và cài CLI bằng npm install -g @usebruno/cli hoặc dùng ảnh Docker để không phải cài Node.js trên máy chạy CI [1][7]. Vì không có máy chủ trung tâm, bài toán vận hành chuyển sang quản lý cấu hình: ai được phép đẩy lên nhánh chính, bộ sưu tập nào là nguồn đúng, quy ước đặt tên thư mục và môi trường.

Đội cần thống nhất định dạng: .bru hay .yml. Vì bộ sưu tập mới mặc định dùng .yml còn ngữ pháp .bru phiên bản 1 là di sản [4], nên chọn một định dạng, ghi vào hướng dẫn nội bộ và kiểm tra khi nâng cấp ứng dụng. Với công ty có CA nội bộ, CLI hỗ trợ --cacert và --ignore-truststore để kiểm thử dịch vụ nội bộ có chứng chỉ riêng [7].

Nâng cấp phiên bản cần có quy trình: bản phát hành mới nhất theo dữ liệu GitHub lúc thu thập là v4.2.1, công bố ngày 30/09/2026. Nên ghim phiên bản CLI trong CI và thử bản mới trên nhánh riêng trước khi đồng loạt nâng cấp trên máy mọi người.

Bảo mật: ngoại tuyến không đồng nghĩa với không có rủi ro

Điểm cộng đầu tiên là mô hình dữ liệu: bộ sưu tập nằm trên máy, và README cam kết không có kế hoạch đồng bộ đám mây [1]. Tuy vậy, tệp bộ sưu tập có thể chứa tập lệnh JavaScript chạy khi gửi yêu cầu. Tài liệu kiến trúc mô tả hai chế độ sandbox: chế độ an toàn mặc định chạy tập lệnh trong QuickJS biên dịch ra WebAssembly, chế độ nhà phát triển dùng node:vm; chế độ được chọn theo cấu hình bảo mật của bộ sưu tập [4]. Do đó bộ sưu tập nhận từ nguồn không tin cậy cần được coi như mã chưa rà soát.

Từ góc nhìn quy trình, việc đưa bộ sưu tập vào Git khiến bí mật dễ bị commit nhầm nếu đội không tách biến môi trường nhạy cảm; đây là cảnh báo dựa trên cách làm chung, còn cơ chế chính xác của Bruno cần đọc ở tài liệu chính thức. Phía ứng dụng, quy tắc kiến trúc yêu cầu bruno-sqlite chỉ chạy ở tiến trình chính và giao diện truy cập dữ liệu qua IPC từng câu lệnh [3][4], giúp giữ ranh giới giữa giao diện và đĩa.

Quy trình báo lỗ hổng: gửi thư tới security@usebruno.com kèm loại lỗi, đường dẫn tệp, cấu hình đặc biệt và các bước tái hiện; không báo trên issue công khai [5]. Tài liệu kiến trúc cũng ghi nhiều phụ thuộc được ghim ở phiên bản chính cũ hơn bản mới nhất, chẳng hạn Redux Toolkit v1 và Electron khoảng 37.6 [4]. Doanh nghiệp nên đưa Bruno vào quy trình quét phụ thuộc và cập nhật định kỳ như mọi ứng dụng máy tính khác.

Giấy phép MIT, nhãn hiệu và ranh giới với bản thương mại

Tệp license.md ở thư mục gốc là giấy phép MIT, bản quyền 2022 Anoop M D, Anusree P S và những người đóng góp, cho phép dùng, sao chép, sửa, hợp nhất, xuất bản, phân phối và bán lại với điều kiện giữ thông báo bản quyền [2]. Mục License trong README cũng trỏ về tệp này [1]. Gói bruno-filestore có tệp LICENSE.md riêng mà nội dung đọc được cũng là MIT với cùng thông báo bản quyền [6]. Danh mục tệp của commit còn cho thấy nhiều gói con khác có tệp giấy phép riêng; bài viết chưa đọc từng tệp, nên không khẳng định chúng giống nhau.

Hai ranh giới cần nhớ. Thứ nhất là nhãn hiệu: README ghi tên Bruno là nhãn hiệu của Anoop M D, còn biểu trưng lấy từ OpenMoji theo giấy phép CC BY-SA 4.0 [1]. Giấy phép MIT không tự động trao quyền dùng tên hay biểu trưng đó cho sản phẩm phái sinh. Thứ hai là bản thương mại: README nói có phiên bản trả phí, còn tài liệu quản trị nói các sản phẩm thương mại được thiết kế để mở rộng giá trị chứ không để chặn tính năng [1][8]. Đó là cam kết của nhà phát triển, bài viết không có cơ sở để đánh giá ranh giới cụ thể.

Giấy phép chỉ áp dụng cho mã nguồn tại commit này. Nó không bao gồm dịch vụ đám mây hay tính năng trả phí nếu có mã riêng, API mà bạn kiểm thử, nội dung bộ sưu tập của bạn hay các thư viện phụ thuộc có giấy phép riêng. Chưa đọc thỏa thuận đóng góp nào, nên bài viết không đưa ra nhận định về CLA.

Chi phí: ít nằm ở giấy phép, nhiều nằm ở việc chuyển thói quen

Với bản mã nguồn mở, giấy phép MIT không thu phí sử dụng [2]. Chi phí lớn nhất là thời gian chuyển các yêu cầu hiện có sang Bruno, viết lại kịch bản kiểm tra thành khẳng định và tập lệnh, và đào tạo đội dùng Git cho bộ sưu tập. Số giờ cụ thể phụ thuộc quy mô kho yêu cầu hiện có.

Tài nguyên cần thiết gồm: một đến hai kỹ sư kiểm thử để thiết kế khung và quy ước; thời gian của lập trình viên backend để bổ sung kịch bản cho API mới; máy trạm thông thường cho ứng dụng đồ họa, không cần phần cứng đặc biệt trong các tài liệu đã đọc; và thời gian chạy CI cho bru run, phụ thuộc số kịch bản và độ chậm của dịch vụ staging.

Nếu doanh nghiệp cân nhắc phiên bản trả phí, hãy lấy đơn giá hiện hành từ trang giá chính thức vào thời điểm mua, vì các tệp đã đọc không có bảng giá [1].

So với các cách khác để giữ và chạy lại yêu cầu API

README tự đặt Bruno đối diện với Postman và các công cụ tương tự, định vị như lựa chọn thay thế dựa trên hệ thống tệp và ngoại tuyến [1]. Bài viết không so sánh tính năng chi tiết với công cụ nào vì chưa đọc tài liệu của họ. Ở mức cách tiếp cận, khác biệt cốt lõi là nơi lưu dữ liệu: tệp trên máy và Git so với không gian làm việc nằm trên dịch vụ của nhà cung cấp.

Phương án thứ hai là viết kiểm thử API bằng mã trong chính ngôn ngữ của dự án, ví dụ một thư viện HTTP cộng khung kiểm thử. Cách này linh hoạt và kiểm soát tối đa, nhưng người không viết mã khó tham gia và việc khám phá tương tác kém thuận tiện hơn. Phương án thứ ba là tập lệnh curl trong kho mã, rất nhẹ nhưng khó quản lý khi số kịch bản lớn. Phương án thứ tư là sinh kiểm thử từ đặc tả OpenAPI, tiện cho kiểm tra hợp đồng nhưng khó thay kịch bản nghiệp vụ nhiều bước.

Bruno nằm ở giữa: có giao diện cho người khám phá, tệp văn bản cho Git, và CLI cho tự động hóa [1][7].

Hạn chế và những trường hợp nên dừng lại

Thứ nhất, tính cộng tác phụ thuộc Git: không có máy chủ trung tâm theo cam kết ngoại tuyến [1], nên các tính năng như bình luận trực tiếp trên yêu cầu hay phân quyền theo vai trò không nên được giả định có sẵn trong bản mở. Bài viết không xác nhận cũng không phủ nhận chúng trong bản trả phí.

Thứ hai, định hướng sản phẩm do đội lõi quyết định. Tài liệu quản trị nói Bruno là dự án do người bảo trì dẫn dắt chứ không do cộng đồng quản trị, giữ lộ trình cuốn chiếu ba tháng, và thường chỉ rà soát đầy đủ pull request khi hạng mục đã vào lộ trình [8]. Doanh nghiệp muốn một tính năng riêng nên đừng mặc định rằng đóng góp sẽ được nhận nhanh.

Thứ ba, hệ thống định dạng đang chuyển tiếp giữa .bru và .yml [4], và tài liệu kiến trúc lưu ý một số gói là di sản hoặc bị bỏ không dùng. Nếu cần công cụ tải, mô phỏng máy chủ, giám sát liên tục hoặc ghi nhận kiểm toán tập trung, đừng dùng Bruno làm lời giải duy nhất.

Thử nghiệm sáu tuần: từ 20 yêu cầu đầu tiên tới cổng CI

Tuần một và hai: chọn một luồng nghiệp vụ, ví dụ tạo và hoàn tất lệnh bảo trì, nhập khoảng hai mươi yêu cầu đã có vào Bruno, tạo hai môi trường staging và thử nghiệm riêng. Tiêu chí: mọi yêu cầu có ít nhất một khẳng định, không có token thật nằm trong kho Git (rà soát bằng quét tự động).

Tuần ba và bốn: đưa bộ sưu tập vào Git, thêm bước CI chạy bru run bằng ảnh Docker chính thức [1][7]. Tiêu chí đề xuất: chạy lặp lại hai lần liên tiếp cho kết quả như nhau trên cùng một phiên bản dịch vụ; thời gian chạy trong ngưỡng mà đội chấp nhận; ghi được tệp kết quả bằng --output [7].

Tuần năm và sáu: mời hai đến ba người ngoài nhóm tạo kịch bản, đo bằng khảo sát ngắn và số lỗi quy ước tên. Điều kiện dừng: nếu cách quản lý bí mật không đáp ứng yêu cầu của bộ phận bảo mật, hoặc đa số thành viên chưa dùng Git không thể theo kịp sau khi được hướng dẫn, thì chuyển sang phương án khác.

Kết luận

Bruno đáng thử như một cách đưa kịch bản gọi API vào cùng kỷ luật với mã nguồn. Điểm hấp dẫn là định dạng văn bản, Git, dòng lệnh và Docker; điểm cần tỉnh táo là nhãn hiệu, ranh giới bản thương mại, cách quản lý bí mật và sự chuyển tiếp định dạng đĩa [1][4].

Hãy thử với một luồng nhỏ, đặt tiêu chí thoát từ đầu, và đọc kỹ tài liệu chính thức về bí mật và giá trước khi mở rộng.

Nguồn và phương pháp

Đây là nghiên cứu bàn giấy, không phải công bố khoa học đã bình duyệt. Bài viết không cài đặt, chạy hay đo Bruno. Mốc nguồn là commit 8833538ce20548f26b88079ce701095e7b06f682 ngày 12/10/2026, kiểm tra ngày 12/10/2026. Các tệp đã đọc: readme.md, license.md, hai tài liệu kiến trúc trong thư mục .claude, security.md, LICENSE.md của bruno-filestore, readme của bruno-cli, governance.md, README của bruno-sqlite, cùng readme của bruno-lang không được trích dẫn [1][2][3][4][5][6][7][8][9].

Bruno được chọn từ kho lưu trữ GitHub Trending do cộng đồng sao lưu, xuất hiện 31 lần từ 07/01/2026 đến 25/09/2026, thuộc nhóm Phát triển và kiểm thử; trang bằng chứng đầu tiên ghi vị trí 11 trong danh sách JavaScript [10]. Kho chỉ có danh sách Python, Go, JavaScript và Swift, thiếu các ngày 03/09/2026 và 12/10/2026, không phải top 100 chính thức. Mọi tình huống Việt Nam, kế hoạch và ngưỡng đo là đề xuất của bài viết.

Xem mã nguồn Bruno trên GitHub

Khám phá nghiên cứu của BDSG Foundation

Trao đổi về ứng dụng công nghệ cho doanh nghiệp