Anda telah membangun skenario pengujian yang solid untuk *endpoint* pembayaran Anda. Ini merangkai tiga permintaan, menegaskan setiap respons, dan selalu berhasil setiap kali Anda mengklik Jalankan. Kemudian *pipeline* Anda membutuhkannya untuk mencakup empat puluh kombinasi *input*, menarik data dari file yang dikelola oleh *QA lead* Anda, dan menjalankan skenario yang sama terhadap *staging* dan produksi dengan kredensial yang berbeda. Jalankan *point-and-click* yang berhasil di laptop Anda tidak dapat diterapkan untuk itu, dan Anda tidak ingin mengkloning skenario sebanyak empat puluh kali.
Bagian terakhir itulah yang ditangani oleh baris perintah. Dengan Apidog, Anda membuat skenario pengujian satu kali di *visual builder*, lalu menjalankannya dari terminal dengan paket apidog-cli. *Flag* yang mengubah satu skenario menjadi eksekusi berbasis data adalah -d, singkatan dari --iteration-data. Ini mengambil file CSV, file JSON, atau kumpulan data yang telah Anda simpan di proyek Apidog Anda, dan menjalankan skenario satu kali per baris, mengikat nilai-nilai setiap baris ke variabel yang direferensikan oleh permintaan Anda.
Bagaimana *flag* -d membaca file
Seluruh fitur terletak pada satu opsi. Berikut adalah bentuk panjang dan pendek, langsung dari apidog run --help:
-d, --iteration-data <path|testDataId> Definisikan data yang digunakan untuk iterasi (baik JSON atau CSV)
<path|testDataId> adalah detail yang sering dilewatkan banyak orang. Argumen ini *overloaded*. Lewatkan sebuah *path* dan CLI akan membaca file lokal dari disk. Lewatkan *ID data uji* dan CLI akan menarik kumpulan data yang telah Anda simpan di dalam proyek Apidog Anda. *Flag* yang sama, dua sumber, dan *runner* akan mencari tahu mana yang Anda berikan.
Bentuk file lokal adalah titik awal yang umum. Arahkan ke file yang relatif terhadap tempat Anda menjalankan perintah:
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 605067 -e 1629989 \
-d ./test-data/checkout-cases.csv -r cli
CLI membuka checkout-cases.csv, menghitung baris di bawah *header*, dan menjalankan skenario 605067 satu kali per baris. Pada setiap *pass*, ia mengikat kolom-kolom ke variabel yang cocok dalam permintaan Anda, memicu skenario, dan merekam hasil iterasi tersebut. Empat puluh baris, empat puluh *pass*, satu skenario.
Formatnya mengikuti file. *Flag* yang sama menerima JSON tanpa opsi tambahan:
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 605067 -e 1629989 \
-d ./test-data/checkout-cases.json -r cli
Anda tidak perlu memberi tahu CLI format mana yang Anda gunakan. Ia membaca ekstensi dan bentuk file. Itu berarti Anda dapat menukar CSV dengan *array* JSON di tengah proyek tanpa menyentuh perintah, selama nama kolom dan kunci JSON selaras dengan variabel yang diharapkan skenario Anda.
Apa yang diharapkan CLI di dalam setiap file
CSV adalah format untuk kasus datar dan tabular. Baris *header* menamai variabel Anda. Setiap baris di bawahnya adalah satu iterasi. Berikut adalah checkout-cases.csv yang sebenarnya untuk *endpoint* diskon:
sku,quantity,coupon,expected_status,expected_total
DESK-01,1,SAVE10,200,89.10
DESK-01,0,SAVE10,422,0
CHAIR-09,3,,200,447.00
DESK-01,1,EXPIRED,410,0
GHOST-99,1,SAVE10,404,0
Lima kolom menjadi lima variabel. Di dalam *body* permintaan, Anda menulis {{sku}} dan {{quantity}}; dalam penegasan, Anda membandingkan respons dengan {{expected_status}} dan {{expected_total}}. *Runner* mengikatnya per baris. Sel coupon yang kosong di baris ketiga menjadi string kosong, yang merupakan kasus tanpa kupon yang ingin Anda cakup.
JSON adalah format ketika kasus Anda membawa struktur bertingkat yang sulit diratakan menjadi kolom. File ini adalah *array* objek, satu objek per iterasi:
[
{
"label": "valid order, two items",
"order": {
"items": [
{ "sku": "DESK-01", "qty": 1 },
{ "sku": "CHAIR-09", "qty": 2 }
],
"shipping": { "country": "US", "method": "ground" }
},
"expected_status": 200
},
{
"label": "unshippable country",
"order": {
"items": [{ "sku": "DESK-01", "qty": 1 }],
"shipping": { "country": "ZZ", "method": "ground" }
},
"expected_status": 422
}
]
Di dalam skenario, Anda mereferensikan {{order}} dan {{expected_status}} dengan cara yang sama, dan *runner* menyerahkan bidang-bidang setiap objek ke iterasi. Bidang label adalah untuk Anda. Ini muncul dalam laporan sehingga *pass* yang gagal berbunyi “negara yang tidak dapat dikirim” (*unshippable country*) alih-alih “iterasi 2,” yang merupakan perbedaan antara diagnosis lima detik dan lima menit.
Beberapa aturan menjaga file-file ini agar tidak menimbulkan masalah di CI:
- Pastikan nama *header* identik dengan nama variabel dalam skenario Anda. Kolom bernama
qtytidak akan terikat pada permintaan yang membaca{{quantity}}. Ketidakcocokan ini adalah alasan paling umum mengapa eksekusi berbasis data berhasil secara lokal tetapi menghasilkan nilai kosong di *pipeline*. - Kutip bidang CSV mana pun yang berisi koma, atau pindahkan file tersebut ke JSON. Bidang teks bebas dengan koma akan terpecah menjadi dua kolom dan menggeser setiap nilai setelahnya.
- Letakkan hasil yang diharapkan dalam data, bukan skenario. Baris pertama mengharapkan 200, baris keempat mengharapkan 410. Jika Anda membuat *hardcode* ekspektasi dalam penegasan, Anda akan kembali ke satu skenario per kasus.
- Komit file-file ini di samping konfigurasi pengujian Anda agar versi mereka sesuai dengan kode yang mereka jalankan. File data adalah bagian dari pengujian, bukan artefak yang terpisah.
Untuk sisi JSONPath dalam menulis penegasan yang membaca nilai-nilai terikat ini, menetapkan penegasan dan mengekstrak variabel dari respons JSON menjelaskan sintaksisnya secara rinci.
Menjalankan dari kumpulan data yang tersimpan alih-alih dari file
Bentuk kedua dari -d adalah yang tidak muncul di sebagian besar panduan. Alih-alih *path*, Anda memberikan *ID data uji*:
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 605067 -e 1629989 \
-d 38291 -r cli
Sekarang CLI mengambil kumpulan data dengan ID tersebut dari proyek Apidog Anda daripada membaca file dari disk *runner*. Ini berguna ketika data berada bersama tim, bukan bersama repositori. *QA lead* Anda mengelola tabel kasus di dalam Apidog, mengeditnya di aplikasi, dan setiap eksekusi CI mengambil versi saat ini tanpa ada yang melakukan *commit* CSV. Skenario, lingkungan, dan data semuanya ada di sisi *server*; perintah hanya menamainya berdasarkan ID.
*Tradeoff*-nya adalah di mana sumber kebenaran Anda berada. CSV yang telah di-*commit* memberi Anda kumpulan data yang dapat di-*diff* dalam *pull request* dan dipatok ke *commit* yang sedang diuji. *ID data uji* yang tersimpan memberi Anda satu tabel bersama yang diedit semua orang di satu tempat. Keduanya tidak salah. Pilih file yang di-*commit* ketika data harus bergerak selaras dengan kode, dan *ID* yang tersimpan ketika data dimiliki oleh orang-orang yang tidak menyentuh repositori.
Menjalankan *offline* dari file yang diekspor
Ada cara ketiga untuk memberi *input* ke CLI, dan ini mengubah bentuk seluruh perintah. Anda dapat mengekspor kasus pengujian dari Apidog sebagai file mandiri dan menjalankan file tersebut secara langsung, tanpa *ID skenario* dan tanpa *round-trip* jaringan untuk mengambil skenario:
apidog run ./checkout.apidog-cli.json -r cli,html
Di sini, argumen pertama adalah file-source, yaitu kasus uji yang diekspor itu sendiri, bukan *flag*. CLI menjalankan apa yang ada di dalam file. Anda tetap melapisi data iterasi di atasnya dengan -d:
apidog run ./checkout.apidog-cli.json -d ./checkout-cases.csv -r cli,junit
Ini penting untuk dua situasi. Pertama adalah *runner* CI yang terisolasi atau terkunci yang tidak dapat mencapai *cloud* Apidog untuk menyelesaikan *ID skenario*; file yang diekspor membawa semua yang dibutuhkan eksekusi. Kedua adalah reproduktifitas: file yang diekspor adalah *snapshot* beku dari skenario pada saat ekspor, sehingga eksekusi darinya tidak terpengaruh oleh seseorang yang mengedit skenario di aplikasi nanti. Untuk mekanisme instalasi dan *first-run* di balik ini, panduan instalasi Apidog CLI mencakup cara menempatkan biner, dan referensi lengkap Apidog CLI mendokumentasikan setiap *flag* dalam satu tabel.
Memadukan -d dengan -n dan *variable overrides*
Eksekusi berbasis data jarang berjalan sendiri. Tiga *flag* selalu berpasangan dengan -d.
-n, --iteration-count menetapkan berapa kali skenario dijalankan. Ketika Anda menyediakan file data, jumlah baris sudah menggerakkan iterasi, jadi Anda biasanya tidak menggunakan -n dan membiarkan file yang memutuskan. Anda menggunakan -n terutama ketika Anda ingin menjalankan tabel lebih dari satu kali, atau ketika Anda menjalankan tanpa file data sama sekali, seperti *soak test* yang mengulang satu skenario tetap:
apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e 1629989 -n 50 -r cli
--env-var dan --global-var menyuntikkan pasangan key=value saat waktu eksekusi tanpa menyentuh lingkungan dalam proyek Anda. Ini adalah cara Anda menjaga rahasia dan konfigurasi per-*pipeline* agar tidak masuk ke skenario maupun file data. File data berisi kasus pengujian; *override* berisi hal-hal yang berubah per eksekusi:
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 605067 -e 1629989 \
-d ./test-data/checkout-cases.csv \
--env-var "base_url=https://staging.internal" \
--global-var "api_key=$RUNTIME_API_KEY" \
-r cli,junit
Pemisahannya disengaja. Data iterasi adalah bagian dari eksekusi yang sama di mana-mana: kasus yang harus ditangani oleh *endpoint* Anda. *Variable overrides* adalah bagian yang berubah per lingkungan: *host*, kunci, *tenant*. Simpan kredensial di *CI secret store* Anda dan lewati melalui --global-var dari variabel lingkungan, seperti yang dilakukan $RUNTIME_API_KEY di atas. Jangan pernah memasukkannya ke dalam CSV, di mana siapa pun yang memiliki akses repositori dapat membacanya.
Membaca hasil per iterasi
Eksekusi berbasis data hanya berguna jika Anda dapat mengetahui baris mana yang gagal. *Flag reporter* memutuskan apa yang Anda dapatkan kembali.
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 605067 -e 1629989 \
-d ./test-data/checkout-cases.csv \
-r cli,junit --out-dir ./test-reports
-r cli mencetak rincian per-iterasi yang mudah dibaca ke terminal, yang Anda *scan* dalam *log build*. -r junit menulis JUnit XML, format yang hampir setiap *dashboard* CI parses menjadi pohon *pass/fail*, sehingga baris yang gagal muncul sebagai pengujian gagal bernama alih-alih teks *log* yang terkubur. Anda juga dapat memberikan html dan json; html memberikan laporan yang dapat dijelajahi untuk diarsipkan sebagai artefak *build*, dan json memberikan *output* terstruktur mentah jika Anda memproses hasil. --out-dir mengontrol di mana file disimpan sehingga Anda dapat menyimpannya sebagai artefak.
Secara *default*, eksekusi berhenti pada penegasan pertama yang gagal. Untuk tabel data yang luas, ini biasanya merupakan panggilan yang salah, karena Anda ingin melihat setiap baris yang gagal dalam satu *pass*, bukan memperbaiki satu dan menjalankan ulang untuk menemukan yang berikutnya. Ubah perilaku dengan --on-error:
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 605067 -e 1629989 \
-d ./checkout-cases.csv \
--on-error continue \
-r cli,junit --out-dir ./test-reports
--on-error continue menjalankan setiap iterasi bahkan ketika iterasi sebelumnya gagal, sehingga satu laporan menunjukkan baris dua, tujuh, dan sembilan belas rusak sekaligus. Eksekusi tetap berakhir dengan kode keluar bukan nol jika ada yang gagal, jadi ini tetap menjadi *gate* yang nyata. --on-error end adalah *default fast-fail* untuk pemeriksaan *smoke* cepat; ignore adalah untuk langkah yang jarang diketahui *flaky* yang tidak ingin Anda menggagalkan eksekusi.
Mendebug *binding* yang diam-diam tidak melakukan apa-apa
Mode kegagalan yang paling membuang waktu pada eksekusi berbasis data bukanlah penegasan merah. Ini adalah eksekusi hijau yang tidak menguji apa pun, karena data tidak pernah terikat pada permintaan. Permintaan terpicu dengan nilai kosong, *endpoint* mengembalikan 200 untuk *payload* kosong, dan penegasan kebetulan berhasil. Cakupan terlihat baik-baik saja; padahal tidak.
Ketika eksekusi berbasis data berperilaku aneh, tambahkan --verbose:
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 605067 -e 1629989 \
-d ./test-data/checkout-cases.csv \
--verbose -r cli
--verbose mencetak permintaan dan respons lengkap untuk setiap iterasi. Lihat *body* permintaan yang sebenarnya dikirim oleh *runner*. Jika Anda melihat {{sku}} di sana tidak diganti, atau nilai yang kosong padahal sel CSV tidak kosong, *binding* rusak. Tiga penyebab umum, berdasarkan seberapa sering mereka terjadi:
- Nama kolom dan nama variabel tidak cocok. *Header* CSV adalah
product_skudan permintaan membaca{{sku}}. Ganti nama salah satunya agar identik. - Koma yang salah membagi baris CSV. Satu bidang teks bebas yang tidak dikutip menggeser setiap kolom setelahnya, sehingga
expected_statussekarang berisi apa yang seharusnya ada di kolom berikutnya. Kutip bidang tersebut atau alihkan file ke JSON. - *Path* ke file data salah relatif terhadap direktori kerja di CI. Ini teratasi dengan baik di laptop Anda dan diam-diam tidak membaca apa pun di *pipeline*. Gunakan *path* relatif terhadap *repo root* yang dihasilkan oleh langkah *checkout*, dan konfirmasikan file tersebut ada di langkah sebelum eksekusi.
Aturan umumnya: ketika iterasi berhasil tetapi Anda curiga seharusnya tidak, baca satu permintaan *verbose* sebelum Anda mempercayai hasil hijau. Pengujian yang berjalan terhadap *input* kosong lebih buruk daripada tidak ada pengujian, karena ini memberi tahu Anda bahwa semuanya baik-baik saja sementara *endpoint* tidak teruji.
Menghubungkannya ke CI
Keuntungannya adalah seluruh tabel berjalan pada setiap perubahan tanpa ada yang mengklik Jalankan. Berikut adalah *job* GitHub Actions yang menginstal CLI dan menjalankan skenario berbasis CSV pada setiap *pull request*:
name: Data-driven API tests
on: [pull_request]
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Apidog CLI
run: npm install -g apidog-cli
- name: Run data-driven scenario
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
run: |
apidog run --access-token $APIDOG_ACCESS_TOKEN \
-t 605067 -e 1629989 \
-d ./test-data/checkout-cases.csv \
--on-error continue \
-r cli,junit --out-dir ./test-reports
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: api-test-report
path: ./test-reports
Token berasal dari secrets.APIDOG_ACCESS_TOKEN, yang diatur sekali di pengaturan repositori. --on-error continue mengumpulkan setiap baris yang gagal ke dalam satu laporan daripada berhenti pada yang pertama. if: always() pada unggahan menjaga laporan tetap ada bahkan ketika eksekusi gagal, yaitu saat Anda paling ingin membacanya. Ganti *path* CSV dengan file JSON, atau dengan *ID data uji* yang tersimpan, dan tidak ada yang lain yang berubah.
Tiga langkah yang sama dapat diterapkan pada sistem CI mana pun: instal Node.js dan CLI, paparkan token sebagai variabel lingkungan, panggil apidog run dengan -d. GitLab CI, Jenkins, CircleCI, dan lainnya tidak memerlukan penulisan ulang pengujian Anda per platform. Untuk panduan yang lebih mendalam tentang sisi Actions, lihat mengotomatiskan pengujian API di GitHub Actions, dan untuk seluruh permukaan *flag* CLI di seluruh *reporter*, penanganan kesalahan, dan TLS, panduan lengkap Apidog CLI menyajikan setiap opsi.
Alur kerja yang skalabel tanpa memperbesar pengujian
Mulailah dengan satu skenario dan tiga baris. Buat skenario di aplikasi dengan referensi variabel dalam permintaan dan hasil yang diharapkan dalam penegasan. Tulis CSV dengan *happy path*, kegagalan yang diketahui, dan satu kasus batas. Jalankan secara lokal dengan -d sampai ketiga iterasi berperilaku sesuai.
Kemudian kembangkan data, bukan skenario. Setiap laporan *bug* menjadi baris baru dengan *output* yang diharapkan yang benar. *Bug* tersebut berubah menjadi kasus regresi permanen, dan Anda tidak pernah menulis pengujian baru; Anda menambahkan baris ke file. Selama beberapa bulan, file tersebut mengumpulkan masalah nyata yang dihadapi *endpoint* Anda dalam produksi.
Terakhir, masukkan perintah apidog run -d ke CI dengan --on-error continue dan *reporter* junit. Kini, perubahan yang merusak baris kupon kedaluwarsa akan menggagalkan *build* saat itu juga setelah di-*push*, dengan iterasi bernama yang langsung menunjuk ke kasus yang rusak. Skenario tetap menjadi hal kecil yang mudah dibaca tidak peduli seberapa lebar tabelnya. Itu adalah kemenangan berlipat ganda: cakupan bertambah melalui entri data, dan pemeliharaan tetap stabil.
Jika Anda masih memutuskan apakah *runner* CLI seperti ini cocok untuk *stack* Anda dibandingkan dengan *framework code-first*, rincian di alat mana yang harus dipilih untuk pengujian API berbasis data dengan CSV atau JSON membandingkan pendekatan-pendekatan tersebut, dan Apidog CLI vs Newman membahas analog *command-line* terdekat dari dunia Postman.
Pertanyaan yang Sering Diajukan
Bisakah -d menerima *file path* dan kumpulan data yang tersimpan? *Flag* -d menerima salah satu per eksekusi: *path* CSV atau JSON lokal, atau *ID data uji* yang menunjuk ke kumpulan data yang disimpan di proyek Apidog Anda. Anda memberikan satu nilai. Gunakan *path* file ketika data harus di-*versioning* dengan repositori Anda, dan *ID* yang tersimpan ketika tabel bersama berada di aplikasi dan Anda tidak ingin melakukan *commit* salinannya.
Apakah saya harus memberi tahu CLI apakah file saya berformat CSV atau JSON? Tidak. *Runner* membaca format dari file itu sendiri, jadi *flag* -d yang sama menangani keduanya. Pastikan nama kolom Anda (CSV) atau kunci objek (JSON) cocok dengan nama variabel yang direferensikan skenario Anda, dan Anda dapat beralih format tanpa mengubah perintah.
Apa yang terjadi jika saya menggunakan -d dan -n bersamaan? Jumlah baris file data menggerakkan jumlah iterasi, jadi -n biasanya tidak diperlukan dengan -d. Gunakan -n ketika Anda ingin mengulang eksekusi tanpa file data, seperti *soak test*, atau ketika Anda secara spesifik ingin menjalankan seluruh tabel lebih dari sekali.
Mengapa eksekusi berbasis data saya berhasil tanpa menguji apa pun? Penyebab paling umum adalah *binding* yang tidak pernah terjadi: nama kolom yang tidak cocok dengan nama variabel, atau *path* file yang salah di CI yang tidak membaca apa pun. Jalankan sekali dengan --verbose dan periksa *body* permintaan yang dikirim CLI. Jika Anda melihat {{variabel}} yang tidak tergantikan atau nilai kosong, perbaiki ketidakcocokan nama atau *path* sebelum mempercayai hasil hijau.
Bagaimana cara menjaga kredensial agar tidak masuk ke file data saya? Jaga token dan kunci agar tidak masuk ke CSV atau JSON sepenuhnya. Lewatkan saat waktu eksekusi dengan --global-var atau --env-var dari *CI secret store* Anda, seperti cara Anda melewatkan --global-var "api_key=$RUNTIME_API_KEY". File data harus berisi *input* pengujian dan hasil yang diharapkan, bukan apa pun yang mengautentikasi eksekusi.
Bisakah saya menjalankan data yang sama terhadap *staging* dan produksi? Ya. Biarkan skenario dan file data tetap, lalu alihkan target dengan -e. Arahkan pemeriksaan *pull request* ke *ID lingkungan staging* dan pengujian *smoke* pasca-deploy ke produksi menggunakan skenario yang sama dan data yang sama, hanya dengan nilai -e yang berbeda. Memisahkan lingkungan dari data adalah alasan utama mengapa ini berfungsi.
Kesimpulan
*Flag* -d adalah keseluruhan cerita berbasis data untuk Apidog CLI, dan ini lebih fleksibel daripada yang terlihat pada awalnya. Ini membaca file CSV atau JSON lokal, atau kumpulan data yang disimpan di proyek Anda berdasarkan ID. Ini berpasangan dengan -n untuk pengulangan, dengan --env-var dan --global-var untuk konfigurasi per eksekusi, dan dengan --on-error continue sehingga satu eksekusi menampilkan setiap baris yang gagal. Jalankan dari *ID skenario* secara *online* atau dari file yang diekspor secara *offline*, dan baca hasilnya per iterasi melalui *reporter* junit dan cli.
Bangun skenario sekali, deskripsikan setiap kasus sebagai baris, dan biarkan *runner* memperluas cakupan Anda setiap kali seseorang menambahkan baris ke file. Unduh Apidog, arahkan apidog run ke file data pertama Anda, dan ubah satu skenario menjadi tabel kasus yang berjalan pada setiap *push*.
