Rumah > pembangunan bahagian belakang > Golang > Pengujian Pelanggan HTTP yang Mudah dalam Go

Pengujian Pelanggan HTTP yang Mudah dalam Go

王林
Lepaskan: 2024-07-17 12:24:28
asal
1221 orang telah melayarinya

Effortless HTTP Client Testing in Go

pengenalan

Sebagai jurutera perisian, anda mungkin biasa menulis kod untuk berinteraksi dengan perkhidmatan HTTP luaran. Lagipun, ia adalah salah satu perkara yang paling biasa kita lakukan! Sama ada mengambil data, memproses pembayaran dengan pembekal atau mengautomasikan siaran media sosial, aplikasi kami hampir selalu melibatkan permintaan HTTP luaran. Untuk memastikan perisian kami boleh dipercayai dan boleh diselenggara, kami memerlukan cara untuk menguji kod yang bertanggungjawab untuk melaksanakan permintaan ini dan mengendalikan ralat yang mungkin berlaku. Ini memberi kita beberapa pilihan:

  • Laksanakan pembungkus klien yang boleh dipermainkan oleh kod aplikasi utama, yang masih meninggalkan jurang dalam ujian
  • Uji penghuraian respons dan pengendalian berasingan daripada pelaksanaan permintaan sebenar. Walaupun mungkin idea yang baik untuk menguji unit peringkat rendah ini secara individu, alangkah baiknya jika perkara itu dapat dibincangkan dengan mudah bersama dengan permintaan sebenar
  • Alihkan ujian ke ujian integrasi yang boleh melambatkan pembangunan dan tidak dapat menguji beberapa senario ralat dan mungkin terjejas oleh kebolehpercayaan perkhidmatan lain

Pilihan ini tidak begitu buruk, terutamanya jika semuanya boleh digunakan bersama, tetapi kami mempunyai pilihan yang lebih baik: ujian VCR.

Ujian VCR, dinamakan sempena perakam kaset video, ialah sejenis ujian olok-olok yang menjana lekapan ujian daripada permintaan sebenar. Lekapan merekodkan permintaan dan respons untuk digunakan semula secara automatik dalam ujian akan datang. Walaupun anda mungkin perlu mengubah suai lekapan selepas itu untuk mengendalikan input berasaskan masa dinamik atau mengalih keluar bukti kelayakan, ia adalah lebih mudah daripada mencipta olok-olok dari awal. Terdapat beberapa faedah tambahan untuk ujian VCR:

  • Laksanakan kod anda sehingga ke peringkat HTTP, supaya anda boleh menguji aplikasi anda dari hujung ke hujung
  • Anda boleh mengambil respons dunia sebenar dan mengubah suai lekapan yang dijana untuk meningkatkan masa tindak balas, menyebabkan pengehadan kadar, dsb. untuk menguji senario ralat yang tidak selalunya berlaku secara organik
  • Jika kod anda menggunakan pakej/perpustakaan luaran untuk berinteraksi dengan API, anda mungkin tidak tahu dengan tepat rupa permintaan dan respons, jadi ujian VCR boleh mengetahuinya secara automatik
  • Lekapan yang dijana juga boleh digunakan untuk ujian nyahpepijat dan memastikan kod anda melaksanakan permintaan yang dijangkakan

Menyelam Lebih Dalam menggunakan Go

Sekarang anda melihat motivasi di sebalik ujian VCR, mari kita kaji lebih mendalam cara melaksanakannya dalam Go menggunakan dnaeon/go-vcr.

Pustaka ini disepadukan dengan lancar ke dalam mana-mana kod klien HTTP. Jika kod pustaka pelanggan anda belum membenarkan menetapkan *http.Client atau http.Transport Pelanggan, anda harus menambahnya sekarang.

Bagi mereka yang tidak biasa, http.Transport ialah pelaksanaan http.RoundTripper, yang pada asasnya ialah perisian tengah sisi klien yang boleh mengakses permintaan/tindak balas. Ia berguna untuk melaksanakan percubaan semula automatik pada respons 500 tahap atau 429 (had kadar), atau menambah metrik dan mengelog permintaan. Dalam kes ini, ia membenarkan go-vcr untuk mengosongkan semula permintaan ke pelayan HTTP dalam prosesnya sendiri.

Contoh Pemendek URL

Mari kita mulakan dengan contoh mudah. Kami ingin membuat pakej yang membuat permintaan kepada API https://cleanuri.com percuma. Pakej ini akan menyediakan satu fungsi: Shorten(string) (string, error)

Memandangkan ini adalah API percuma, mungkin kita hanya boleh mengujinya dengan membuat permintaan terus ke pelayan? Ini mungkin berkesan, tetapi boleh mengakibatkan beberapa masalah:

  • Pelayan mempunyai had kadar 2 permintaan/saat yang boleh menjadi isu jika kami mempunyai banyak ujian
  • Jika pelayan rosak atau mengambil sedikit masa untuk bertindak balas, ujian kami mungkin gagal
  • Walaupun URL yang dipendekkan dicache, kami tidak mempunyai jaminan bahawa kami akan mendapat output yang sama setiap kali
  • Adalah kurang ajar untuk menghantar trafik yang tidak perlu kepada API percuma!

Ok, bagaimana jika kita mencipta antara muka dan mengejeknya? Pakej kami sangat mudah, jadi ini akan merumitkannya. Memandangkan perkara peringkat terendah yang kami gunakan ialah *http.Client, kami perlu menentukan antara muka baharu di sekelilingnya dan melaksanakan olok-olok.

Pilihan lain adalah untuk mengatasi URL sasaran untuk menggunakan port tempatan yang disediakan oleh httptest.Server. Ini pada asasnya adalah versi ringkas tentang apa yang dilakukan oleh go-vcr dan akan mencukupi dalam kes mudah kami, tetapi tidak akan dapat diselenggara dalam senario yang lebih kompleks. Malah dalam contoh ini, anda akan melihat cara mengurus lekapan yang dijana adalah lebih mudah daripada mengurus pelaksanaan pelayan olok-olok yang berbeza.

Memandangkan antara muka kami telah ditakrifkan dan kami mengetahui beberapa input/output yang sah daripada mencuba UI di https://cleanuri.com, ini adalah peluang yang baik untuk mempraktikkan pembangunan dipacu ujian. Kami akan mulakan dengan melaksanakan ujian mudah untuk fungsi Shorten kami:

package shortener_test

func TestShorten(t *testing.T) {
    shortened, err := shortener.Shorten("https://dev.to/calvinmclean")
    if err != nil {
        t.Errorf("unexpected error: %v", err)
    }

    if shortened != "https://cleanuri.com/7nPmQk" {
        t.Errorf("unexpected result: %v", shortened)
    }
}
Salin selepas log masuk

Agak mudah! Kami tahu bahawa ujian akan gagal untuk disusun kerana shortener.Shorten tidak ditakrifkan, tetapi kami tetap menjalankannya supaya membetulkannya akan lebih memuaskan.

Akhir sekali, mari kita teruskan dan laksanakan fungsi ini:

package shortener

var DefaultClient = http.DefaultClient

const address = "https://cleanuri.com/api/v1/shorten"

// Shorten will returned the shortened URL
func Shorten(targetURL string) (string, error) {
    resp, err := DefaultClient.PostForm(
        address,
        url.Values{"url": []string{targetURL}},
    )
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        return "", fmt.Errorf("unexpected response code: %d", resp.StatusCode)
    }

    var respData struct {
        ResultURL string `json:"result_url"`
    }
    err = json.NewDecoder(resp.Body).Decode(&respData)
    if err != nil {
        return "", err
    }

    return respData.ResultURL, nil
}
Salin selepas log masuk

Kini ujian kami lulus! Ia sama memuaskan seperti yang saya janjikan.

Untuk mula menggunakan VCR, kita perlu memulakan Perakam dan mengatasi shortener.DefaultClient pada permulaan ujian:

func TestShorten(t *testing.T) {
    r, err := recorder.New("fixtures/dev.to")
    if err != nil {
        t.Fatal(err)
    }
    defer func() {
        require.NoError(t, r.Stop())
    }()

    if r.Mode() != recorder.ModeRecordOnce {
        t.Fatal("Recorder should be in ModeRecordOnce")
    }

    shortener.DefaultClient = r.GetDefaultClient()

    // ...
Salin selepas log masuk

Jalankan ujian untuk menjana lekapan/dev.to.yaml dengan butiran tentang permintaan dan tindak balas ujian. Apabila kami menjalankan semula ujian, ia menggunakan respons yang direkodkan dan bukannya menghubungi pelayan. Jangan hanya mengambil kata-kata saya untuk itu; matikan WiFi komputer anda dan jalankan semula ujian!

Anda juga mungkin perasan bahawa masa yang diambil untuk menjalankan ujian adalah agak konsisten sejak go-vcr merekod dan memainkan semula tempoh respons. Anda boleh mengubah suai medan ini secara manual dalam YAML untuk mempercepatkan ujian.

Kesilapan Mengejek

Untuk menunjukkan lebih lanjut manfaat ujian jenis ini, mari tambah ciri lain: cuba semula selepas 429 respons kerana pengehadan kadar. Memandangkan kami tahu had kadar API adalah sesaat, Shorten boleh menunggu sebentar secara automatik dan mencuba semula jika ia menerima kod respons 429.

Saya cuba menghasilkan semula ralat ini menggunakan API secara langsung, tetapi nampaknya ia bertindak balas dengan URL sedia ada daripada cache sebelum mempertimbangkan had kadar. Daripada mencemarkan cache dengan URL palsu, kami boleh mencipta olok-olok kami sendiri kali ini.

Ini adalah proses yang mudah kerana kami telah menjana lekapan. Selepas menyalin/menampal lekapan/dev.to.yaml ke fail baharu, salin interaksi permintaan/tindak balas yang berjaya dan tukar kod respons pertama daripada 200 kepada 429. Lekapan ini meniru percubaan semula yang berjaya selepas kegagalan mengehadkan kadar.

Satu-satunya perbezaan antara ujian ini dan ujian asal ialah nama fail lekapan baharu. Output yang dijangkakan adalah sama kerana Shorten harus mengendalikan ralat. Ini bermakna kita boleh membuang ujian dalam satu gelung untuk menjadikannya lebih dinamik:

func TestShorten(t *testing.T) {
    fixtures := []string{
        "fixtures/dev.to",
        "fixtures/rate_limit",
    }

    for _, fixture := range fixtures {
        t.Run(fixture, func(t *testing.T) {
            r, err := recorder.New(fixture)
            if err != nil {
                t.Fatal(err)
            }
            defer func() {
                require.NoError(t, r.Stop())
            }()

            if r.Mode() != recorder.ModeRecordOnce {
                t.Fatal("Recorder should be in ModeRecordOnce")
            }

            shortener.DefaultClient = r.GetDefaultClient()

            shortened, err := shortener.Shorten("https://dev.to/calvinmclean")
            if err != nil {
                t.Errorf("unexpected error: %v", err)
            }

            if shortened != "https://cleanuri.com/7nPmQk" {
                t.Errorf("unexpected result: %v", shortened)
            }
        })
    }
}
Salin selepas log masuk

Sekali lagi, ujian baru gagal. Kali ini disebabkan respons 429 yang tidak dikendalikan, jadi mari kita laksanakan ciri baharu untuk lulus ujian. Untuk mengekalkan kesederhanaan, fungsi kami mengendalikan ralat menggunakan masa. Tidur dan panggilan rekursif daripada menangani kerumitan mempertimbangkan percubaan semula maksimum dan pengunduran eksponen:

func Shorten(targetURL string) (string, error) {
    // ...
    switch resp.StatusCode {
    case http.StatusOK:
    case http.StatusTooManyRequests:
        time.Sleep(time.Second)
        return Shorten(targetURL)
    default:
        return "", fmt.Errorf("unexpected response code: %d", resp.StatusCode)
    }
    // ...
Salin selepas log masuk

Sekarang jalankan ujian sekali lagi dan lihat mereka lulus!

Ambil langkah lebih jauh sendiri dan cuba tambahkan ujian untuk permintaan buruk, yang akan berlaku apabila menggunakan URL yang tidak sah seperti url-palsu saya.

Kod penuh untuk contoh ini (dan ujian permintaan buruk) tersedia di Github.

Kesimpulan

Faedah ujian VCR jelas daripada contoh mudah ini, tetapi ia lebih berkesan apabila berurusan dengan aplikasi kompleks yang permintaan dan responsnya sukar digunakan. Daripada berurusan dengan ejekan yang membosankan atau memilih untuk tiada ujian sama sekali, saya menggalakkan anda mencuba ini dalam aplikasi anda sendiri. Jika anda sudah bergantung pada ujian penyepaduan, bermula dengan VCR adalah lebih mudah kerana anda sudah mempunyai permintaan sebenar yang boleh menjana lekapan.

Lihat lebih banyak dokumentasi dan contoh dalam repositori Github pakej: https://github.com/dnaeon/go-vcr

Atas ialah kandungan terperinci Pengujian Pelanggan HTTP yang Mudah dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan