---
title: "Metode Pengujian `test::nginx`: Konfigurasi, Mengirim Permintaan, dan Menangani Respons - API7.ai"
description: "Artikel ini menjelaskan cara menggunakan test::nginx untuk mengirim permintaan dan menangani respons dalam sebuah test case."
url: "https://api7.ai/id/learning-center/openresty/all-inclusive-testing-methods-test-nginx"
---

# Metode Pengujian \`test::nginx\`: Konfigurasi, Mengirim Permintaan, dan Menangani Respons

API7.ai

November 18, 2022

[OpenResty (NGINX + Lua)](https://api7.ai/learning-center/openresty)

Pada artikel terakhir, kita sudah mendapatkan gambaran pertama tentang `test::nginx` dan menjalankan contoh paling sederhana. Namun, dalam proyek open-source nyata, kasus uji yang ditulis dalam `test::nginx` jauh lebih kompleks dan sulit untuk dikuasai dibandingkan dengan kode contoh. Jika tidak, itu tidak akan disebut sebagai hambatan.

Dalam artikel ini, saya akan membawa Anda melalui perintah dan metode pengujian yang sering digunakan dalam `test::nginx`, sehingga Anda dapat memahami sebagian besar set kasus uji dalam proyek OpenResty dan memiliki kemampuan untuk menulis kasus uji yang lebih realistis. Bahkan jika Anda belum berkontribusi kode ke OpenResty, mengenal kerangka pengujian OpenResty akan menjadi inspirasi besar bagi Anda untuk merancang dan menulis kasus uji dalam pekerjaan Anda.

Pengujian `test::nginx` pada dasarnya menghasilkan `nginx.conf` dan memulai proses NGINX berdasarkan konfigurasi setiap kasus uji. Kemudian, itu mensimulasikan permintaan klien dengan badan permintaan dan header yang ditentukan. Selanjutnya, kode Lua dalam kasus uji memproses permintaan dan memberikan respons. Pada saat ini, `test::nginx` memparsing informasi kritis seperti badan respons, header respons, dan log kesalahan dan membandingkannya dengan konfigurasi pengujian. Jika ada perbedaan, pengujian gagal dengan kesalahan; jika tidak, pengujian berhasil.

`test::nginx` menyediakan banyak primitif DSL (Domain-specific language). Saya telah membuat klasifikasi sederhana sesuai dengan konfigurasi NGINX, mengirim permintaan, memproses respons, dan memeriksa log. 20% dari fungsionalitas ini dapat mencakup 80% dari skenario aplikasi, jadi kita harus memahaminya dengan baik. Adapun primitif dan penggunaan yang lebih lanjut, kita akan membahasnya di artikel berikutnya.

## Konfigurasi NGINX

Mari kita lihat terlebih dahulu konfigurasi NGINX. Primitif `test::nginx` dengan kata kunci "config" terkait dengan konfigurasi NGINX, seperti `config`, `stream_config`, `http_config`, dll.

Fungsinya sama: menyisipkan konfigurasi NGINX yang ditentukan ke dalam konteks NGINX yang berbeda. Konfigurasi ini dapat berupa perintah NGINX atau kode Lua yang dibungkus dalam `content_by_lua_block`.

Saat melakukan pengujian unit, `config` adalah primitif yang paling sering digunakan di mana kita memuat pustaka Lua dan memanggil fungsi untuk pengujian white-box. Berikut adalah cuplikan kode pengujian, yang tidak dapat dijalankan sepenuhnya. Ini berasal dari proyek open-source nyata, jadi jika Anda tertarik, Anda dapat mengklik [tautan](https://github.com/apache/apisix/blob/master/t/plugin/key-auth.t#L11) untuk melihat pengujian lengkap, atau Anda dapat mencoba menjalankannya secara lokal.

```
=== TEST 1: sanity
--- config
    location /t {
        content_by_lua_block {
            local plugin = require("apisix.plugins.key-auth")
            local ok, err = plugin.check_schema({key = 'test-key'})
            if not ok then
                ngx.say(err)
            end
            ngx.say("done")
        }
    }
```

Tujuan dari kasus uji ini adalah untuk menguji apakah fungsi `check_schema` dalam file kode `plugins.key-auth` berfungsi dengan baik. Ini menggunakan perintah NGINX `content_by_lua_block` dalam `location /t` untuk memerlukan modul yang akan diuji dan memanggil fungsi yang perlu diperiksa secara langsung.

Ini adalah cara umum pengujian white-box dalam `test::nginx`. Namun, konfigurasi ini saja tidak cukup untuk menyelesaikan pengujian, jadi mari kita lanjutkan dan lihat bagaimana cara mengirim permintaan klien.

## Mengirim Permintaan

Mensimulasikan klien yang mengirim permintaan melibatkan cukup banyak detail, jadi mari kita mulai dengan yang paling sederhana - mengirim satu permintaan.

### `request`

Lanjutkan dengan kasus uji di atas, jika kita ingin kode pengujian unit dijalankan, maka kita harus memulai permintaan HTTP ke alamat `/t` yang ditentukan dalam konfigurasi, seperti yang ditunjukkan dalam kode pengujian berikut:

```
--- request
GET /t
```

Kode ini mengirim permintaan `GET` ke `/t` dalam primitif permintaan. Di sini, kita tidak menentukan alamat IP, nama domain, atau port akses, juga tidak menentukan apakah itu `HTTP 1.0` atau `HTTP 1.1`. Semua detail ini disembunyikan oleh `test::nginx`, jadi kita tidak perlu memikirkannya. Ini adalah salah satu manfaat DSL - kita hanya perlu fokus pada logika bisnis tanpa terganggu oleh semua detail.

Selain itu, ini memberikan fleksibilitas parsial. Misalnya, defaultnya adalah protokol untuk `HTTP 1.1`, atau jika kita ingin menguji `HTTP 1.0`, kita dapat menentukannya secara terpisah:

```
--- request
GET /t  HTTP/1.0
```

Selain metode `GET`, metode `POST` juga perlu didukung. Dalam contoh berikut, kita dapat `POST` string `hello world` ke alamat yang ditentukan.

```
--- request
POST /t  
hello world
```

Sekali lagi, `test::nginx` menghitung panjang badan permintaan untuk Anda di sini, dan menambahkan header permintaan `host` dan `connection` untuk memastikan bahwa ini adalah permintaan normal secara otomatis.

Tentu saja, kita dapat menambahkan komentar untuk membuatnya lebih mudah dibaca. Yang dimulai dengan `#` akan dikenali sebagai komentar kode.

```
--- request
# post request
POST /t  
hello world
```

Permintaan juga mendukung mode yang lebih kompleks dan fleksibel, yang menggunakan `eval` sebagai filter untuk menyematkan kode Perl secara langsung karena `test::nginx` ditulis dalam Perl. Jika bahasa DSL saat ini tidak memenuhi kebutuhan Anda, `eval` adalah "senjata pamungkas" untuk menjalankan kode Perl secara langsung.

Untuk penggunaan `eval`, mari kita lihat beberapa contoh sederhana di sini, dan kita akan melanjutkan dengan yang lebih kompleks di artikel berikutnya.

```
--- request eval
"POST /t
hello\x00\x01\x02
world\x03\x04\xff"
```

Dalam contoh pertama, kita menggunakan `eval` untuk menentukan karakter yang tidak dapat dicetak, yang merupakan salah satu kegunaannya. Konten di antara tanda kutip ganda akan diperlakukan sebagai string Perl dan kemudian diteruskan ke `request` sebagai argumen.

Berikut adalah contoh yang lebih menarik:

```
--- request eval
"POST /t\n" . "a" x 1024
```

Namun, untuk memahami contoh ini, kita perlu mengetahui sedikit tentang string dalam Perl, jadi saya perlu menyebutkan dua poin di sini.

- Dalam Perl, kita menggunakan titik untuk mewakili penggabungan string. Bukankah ini agak mirip dengan dua titik dalam `Lua`?
- Huruf kecil `x` menunjukkan berapa kali karakter diulang. Misalnya, `"a" x 1024` di atas berarti karakter "a" diulang 1024 kali.

Jadi, contoh kedua berarti metode `POST` mengirim permintaan yang berisi `1024` karakter `a` ke alamat `/t`.

### `pipelined_requests`

Setelah memahami cara mengirim satu permintaan, mari kita lihat cara mengirim beberapa permintaan. Dalam `test::nginx`, kita dapat menggunakan primitif `pipelined_requests` untuk mengirim beberapa permintaan secara berurutan dalam koneksi `keep-alive` yang sama:

```
--- pipelined_requests eval
["GET /hello", "GET /world", "GET /foo", "GET /bar"]
```

Misalnya, contoh ini akan mengakses keempat API ini secara berurutan dalam koneksi yang sama. Ada dua keuntungan tentang ini:

- Yang pertama adalah banyak kode pengujian yang berulang dapat dihilangkan, dan empat kasus uji dapat dikompres menjadi satu.
- Yang kedua dan paling penting adalah kita dapat menggunakan permintaan pipelined untuk mendeteksi apakah logika kode akan memiliki pengecualian dalam kasus beberapa akses.

Anda mungkin bertanya-tanya, saya menulis beberapa kasus uji secara berurutan, maka kode juga akan dieksekusi beberapa kali dalam fase eksekusi. Bukankah itu juga mencakup masalah kedua di atas?

Ini berkaitan dengan mode eksekusi `test::nginx`, yang bekerja berbeda dari yang Anda pikirkan. Setelah setiap kasus uji, `test::nginx` mematikan proses NGINX saat ini, dan semua data dalam memori menghilang. Saat menjalankan kasus uji berikutnya, `nginx.conf` dihasilkan ulang, dan `Worker` NGINX baru dimulai. Mekanisme ini memastikan bahwa kasus uji tidak saling mempengaruhi.

Jadi, ketika kita ingin menguji beberapa permintaan, kita perlu menggunakan primitif `pipelined_requests`. Berdasarkan itu, kita dapat mensimulasikan pembatasan laju, pembatasan konkurensi, dan banyak skenario lain untuk menguji apakah sistem Anda bekerja dengan baik dengan skenario yang lebih realistis dan kompleks. Kita akan membahas ini di artikel berikutnya juga, karena ini akan melibatkan beberapa perintah dan primitif.

### `repeat_each`

Kita baru saja menyebutkan kasus pengujian beberapa permintaan, jadi bagaimana seharusnya kita menjalankan pengujian yang sama beberapa kali?

Untuk masalah ini, `test::nginx` menyediakan pengaturan global: `repeat_each`, yang merupakan fungsi Perl yang defaultnya adalah `repeat_each(1)`, menunjukkan bahwa kasus uji hanya akan dijalankan sekali. Jadi dalam kasus uji sebelumnya, kita tidak perlu repot mengaturnya secara terpisah.

Secara alami, kita dapat mengaturnya sebelum fungsi `run_test()`, misalnya, dengan mengubah argumen menjadi `2`.

```
repeat_each(2);
run_tests();
```

Kemudian, setiap kasus uji dijalankan dua kali, dan seterusnya.

### `more_headers`

Setelah membahas badan permintaan, mari kita lihat header permintaan. Seperti yang kita sebutkan di atas, `test::nginx` mengirim permintaan dengan header `host` dan `connection` secara default. Bagaimana dengan header permintaan lainnya?

`more_headers` dirancang khusus untuk melakukan hal itu.

```
--- more_headers
X-Foo: blah
```

Kita dapat menggunakannya untuk mengatur berbagai header kustom. Jika kita ingin mengatur lebih dari satu header, maka atur lebih dari satu baris:

```
--- more_headers
X-Foo: 3
User-Agent: openresty
```

## Memproses Respons

Setelah mengirim permintaan, bagian terpenting dari `test::nginx` adalah memproses respons, di mana kita akan menentukan apakah respons memenuhi harapan. Di sini kita membaginya menjadi empat bagian dan memperkenalkannya: badan respons, header respons, kode status respons, dan log.

### `response_body`

Pasangan dari primitif permintaan adalah `response_body`, dan berikut adalah contoh dari dua konfigurasi mereka dalam penggunaan:

```
=== TEST 1: sanity
--- config
    location /t {
        content_by_lua_block {
            ngx.say("hello")
        }
    }
--- request
GET /t
--- response_body
hello
```

Kasus uji ini akan berhasil jika badan respons adalah `hello`, dan akan melaporkan kesalahan dalam kasus lain. Tetapi bagaimana kita menguji badan respons yang panjang? Jangan khawatir, `test::nginx` sudah mengurusnya untuk Anda. Ini mendukung deteksi badan respons dengan ekspresi reguler, seperti berikut:

```
--- response_body_like
^he\w+$
```

Ini memungkinkan Anda untuk sangat fleksibel dengan badan respons. Selain itu, `test::nginx` juga mendukung operasi `unlike`:

```
--- response_body_unlike
^he\w+$
```

Pada titik ini, jika badan respons adalah `hello`, pengujian tidak akan berhasil.

Sejalan dengan itu, setelah memahami deteksi satu permintaan, mari kita lihat deteksi beberapa permintaan. Berikut adalah contoh cara menggunakannya dengan `pipelined_requests`:

```
--- pipelined_requests eval
["GET /hello", "GET /world", "GET /foo", "GET /bar"]
--- response_body eval
["hello", "world", "oo", "bar"]
```

Tentu saja, yang penting untuk diperhatikan di sini adalah sebanyak permintaan yang Anda kirim, Anda perlu memiliki sebanyak respons yang sesuai.

### `response_headers`

Kedua, mari kita bicara tentang header respons. Header respons mirip dengan header permintaan di mana setiap baris sesuai dengan kunci dan nilai dari sebuah header.

```
--- response_headers
X-RateLimit-Limit: 2
X-RateLimit-Remaining: 1
```

Seperti deteksi badan respons, header respons juga mendukung ekspresi reguler dan operasi `unlike`, seperti `response_headers_like`, `raw_response_headers_like`, dan `raw_response_headers_unlike`.

### `error_code`

Yang ketiga adalah kode respons. Deteksi kode respons mendukung perbandingan langsung dan juga mendukung operasi `like`, seperti dua contoh berikut:

```
--- error_code: 302
```

```
--- error_code_like: ^(?:500)?$
```

Dalam kasus beberapa permintaan, `error_code` perlu diperiksa beberapa kali:

```
--- pipelined_requests eval
["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
--- error_code eval
[200, 200, 503, 503]
```

### `error_log`

Item pengujian terakhir adalah log kesalahan. Dalam kebanyakan kasus uji, tidak ada log kesalahan yang dihasilkan. Kita dapat menggunakan `no_error_log` untuk mendeteksi:

```
--- no_error_log
[error]
```

Dalam contoh di atas, jika string `[error]` muncul dalam `error.log` NGINX, pengujian akan gagal. Ini adalah fitur yang sangat umum, dan disarankan agar Anda menambahkan deteksi log kesalahan ke semua pengujian normal Anda.

```
--- error_log
hello world
```

Konfigurasi di atas adalah mendeteksi keberadaan `hello world` dalam `error.log`. Tentu saja, Anda dapat menggunakan `eval` yang disematkan dalam kode Perl untuk mengimplementasikan deteksi ekspresi reguler, seperti berikut:

```
--- error_log eval
qr/\[notice\] .*?  \d+ hello world/
```

## Ringkasan

Hari ini, kita belajar cara mengirim permintaan dan menguji respons dalam `test::nginx`, termasuk badan permintaan, header, kode status respons, dan log kesalahan. Kita dapat mengimplementasikan set kasus uji yang lengkap dengan kombinasi primitif ini.

Terakhir, berikut adalah pertanyaan pemikiran: Apa kelebihan dan kekurangan dari `test::nginx`, sebuah DSL abstrak? Jangan ragu untuk meninggalkan komentar dan berdiskusi dengan saya, dan Anda juga dipersilakan untuk membagikan artikel ini untuk berkomunikasi dan berpikir bersama.

Share article link

Share

Related Posts

[![OpenResty FAQ | Struktur Jaringan untuk Pengujian, Fitur Terkait SSL, DSL, Alat \`ab\`](https://static.api7.ai/2022/12/02/63896c177fde1.png)](https://api7.ai/learning-center/openresty/faq-3)

## [OpenResty FAQ | Struktur Jaringan untuk Pengujian, Fitur Terkait SSL, DSL, Alat \`ab\`](https://api7.ai/learning-center/openresty/faq-3)

[![Penggunaan \`test::nginx\` yang Jarang Diketahui](https://static.api7.ai/2022/11/25/63802a7fb4697.png)](https://api7.ai/learning-center/openresty/little-known-usage-of-test-nginx)

## [Penggunaan \`test::nginx\` yang Jarang Diketahui](https://api7.ai/learning-center/openresty/little-known-usage-of-test-nginx)

Table of Contents

- [Konfigurasi NGINX](#konfigurasi-nginx)

- [Mengirim Permintaan](#mengirim-permintaan)

  - [`request`](#request)
  - [`pipelined_requests`](#pipelined_requests)
  - [`repeat_each`](#repeat_each)
  - [`more_headers`](#more_headers)

- [Memproses Respons](#memproses-respons)

  - [`response_body`](#response_body)
  - [`response_headers`](#response_headers)
  - [`error_code`](#error_code)
  - [`error_log`](#error_log)

- [Ringkasan](#ringkasan)
