Apakah ide yang baik untuk memiliki metode pengujian terpisah untuk setiap langkah?

10

Saya sedang menguji api REST. Katakanlah itu mengembalikan struktur JSON. Apa pendekatan terbaik untuk menguji server? Setiap langkah uji hanya dapat berhasil jika semua sebelumnya berhasil.

Struktur A: uji semuanya sekaligus

- Test method 1:
    - make server request
    - assert http response code was 200
    - assert returned file is not empty
    - assert returned file has valid JSON syntax
    - assert returned JSON contains key X

Ini sepertinya menjadi solusi terbaik.

Keuntungan:

  • Hanya satu permintaan server
  • Saya menguji perilaku secara keseluruhan "Apakah server mengembalikan JSON dengan kunci X?"

Struktur B: secara bertahap tambahkan pernyataan untuk setiap tes

 - Test method 1:
     - make server request
     - assert http response code was 200
 - Test method 2:
     - make server request
     - assert returned file is not empty
 - Test method 3:
     - make server request
     - assert returned file has valid JSON syntax
 - Test method 4:
     - make server request
     - assert returned JSON contains key X

Ini adalah bagaimana saya mulai melakukannya dan saya yakin bahwa ini harus menjadi cara untuk pergi karena setiap metode menguji hanya satu hal dan ini menciptakan pemisahan yang lebih baik. Tetapi sekarang saya berpikir, karena ini bukan unit test, pemisahan saya tidak tepat dan saya harus menguji perilaku secara keseluruhan.

Struktur C: membuat permintaan sekali dan menjalankan metode pengujian terpisah pada respons yang di-cache

- make server request and cache it (allow read-only access)

 - Test method 1:
     - assert http response code was 200 on cached server request
 - Test method 2:
     - assert returned file is not empty on cached server request
 - Test method 3:
     - assert returned file has valid JSON syntax on cached server request
 - Test method 4:
     - assert returned JSON contains key X on cached server request

Keuntungan:

  • Tidak ada permintaan server yang berulang (mahal)
  • Masih memiliki metode uji satu-assert

Manakah struktur tes yang paling masuk akal untuk digunakan?

mrplow
sumber
Harap berhenti mengubah pertanyaan Anda setelah itu dengan cara yang membatalkan jawaban yang ada! Terima kasih.
Doc Brown
Maaf karena membuat Anda tidak nyaman, tetapi apakah Anda akan melakukan sebaliknya?
mrplow
Pertama, pikirkan dua kali jika Anda benar-benar perlu mengubah pertanyaan Anda sedemikian rupa. Jika Anda benar-benar berpikir Anda harus menambahkan sesuatu yang membatalkan beberapa jawaban, Anda dapat memberi tahu semua penulis tentang jawaban-jawaban itu dengan meninggalkan komentar di bawah jawaban mereka menanyakan apakah mereka ingin mengubah atau menambahkan sesuatu dalam teks mereka.
Doc Brown
2
Saya benar-benar berasumsi bahwa penulis jawaban diberitahu jika pertanyaannya diubah. Inilah sebabnya saya tidak ingin mengirim spam komentar tanpa pernyataan topik. Saya akan memberi tahu penulis di masa mendatang. Dan terima kasih telah memberikan jawaban untuk pertanyaan saya.
mrplow

Jawaban:

3

Praktik terbaik selalu memiliki tujuan, alasan di baliknya. Itu selalu merupakan ide yang baik untuk mempertimbangkan alasan-alasan ini dalam desain Anda - terutama ketika Anda mencoba untuk memutuskan bagaimana dan seberapa sulit untuk mengikuti praktik terbaik ini.

Dalam hal ini, alasan utama di balik membuat setiap tes tes menjadi satu hal adalah bahwa jika hal pertama gagal, yang kedua tidak akan diuji. Karena terlalu banyak pembuat opini yang tampaknya menemukan manfaat dalam menghancurkan segala sesuatunya menjadi bit terkecil yang mungkin dan membungkus setiap bit dalam mengasapi sebanyak mungkin, ini melahirkan gagasan bahwa setiap tes harus berisi satu pernyataan.

Jangan ikuti ini secara membabi buta. Bahkan jika setiap tes harus menguji satu hal, Anda masih harus mempertimbangkan untuk menentukan seberapa besar atau kecil setiap "hal" itu, dan untuk melakukannya Anda harus mengingat mengapa Anda ingin setiap tes menguji satu hal - untuk memastikan bug pada hal pertama adalah tidak membiarkan hal kedua tidak teruji.

Jadi, Anda perlu bertanya pada diri sendiri - "apakah saya benar-benar membutuhkan jaminan ini di sini?"

Katakanlah ada bug dalam kasus pengujian pertama - kode respons HTTP tidak 200. Jadi Anda mulai meretas kode tersebut, mencari tahu mengapa Anda tidak mendapatkan kode respons yang seharusnya Anda miliki, dan memperbaiki masalahnya. Dan sekarang apa?

  • Jika Anda menjalankan tes secara manual lagi, untuk memverifikasi bahwa perbaikan Anda memang menyelesaikan masalah, Anda harus mengalami masalah lain yang disembunyikan oleh kegagalan pertama.
  • Jika Anda tidak menjalankannya secara manual (mungkin karena terlalu lama?), Dan hanya mendorong perbaikan Anda menunggu server tes otomatis untuk menjalankan semuanya, maka Anda mungkin ingin memasukkan pernyataan berbeda dalam tes yang berbeda. Siklus dalam kasus ini sangat panjang, jadi perlu dilakukan upaya untuk menemukan sebanyak mungkin bug dalam setiap siklus.

Ada beberapa hal yang perlu dipertimbangkan:

Ketergantungan dependensi

Saya tahu tes yang Anda jelaskan hanyalah contoh, dan tes Anda yang sebenarnya mungkin lebih rumit - jadi apa yang akan saya katakan mungkin tidak valid dengan kekuatan sebanyak dalam tes sebenarnya, tetapi mungkin masih agak efektif sehingga Anda mungkin ingin mempertimbangkannya.

Jika Anda memiliki layanan REST (atau protokol HTTP lainnya) yang mengembalikan respons dalam format JSON, Anda biasanya menulis kelas klien sederhana yang memungkinkan Anda menggunakan metode REST seperti metode biasa yang mengembalikan objek biasa. Dengan asumsi bahwa klien memiliki tes terpisah untuk memastikan itu berfungsi, saya akan membuang 3 menegaskan pertama dan hanya menyimpan 4!

Mengapa?

  • Penegasan pertama adalah redundan - kelas klien harus memberikan pengecualian jika kode respons HTTP tidak 200.
  • Penegasan kedua adalah redundan - jika responsnya kosong, objek hasil akan nol atau representasi lain dari objek kosong, dan Anda tidak akan memiliki tempat untuk meletakkan kunci X.
  • Penegasan ketiga berlebihan - jika JSON tidak valid, Anda akan mendapatkan pengecualian saat mencoba menguraikannya.

Jadi Anda tidak perlu menjalankan semua tes ini - jalankan saja tes keempat, dan jika salah satu bug, tiga yang pertama mencoba untuk mendeteksi terjadi tes akan gagal dengan pengecualian yang tepat sebelum Anda bahkan mendapatkan pernyataan yang sebenarnya.

Bagaimana Anda ingin menerima laporan?

Katakanlah Anda tidak mendapatkan email dari server pengujian, tetapi departemen QA yang menjalankan tes dan memberi tahu Anda tentang tes yang gagal.

Jack dari QA mengetuk pintu Anda. Dia mengatakan bahwa metode pengujian pertama gagal, dan metode REST mengembalikan kode respons yang buruk. Anda berterima kasih padanya, dan mulai mencari akar masalahnya.

Kemudian datanglah Jen dari QA, dan katakan bahwa metode pengujian ketiga gagal - metode REST tidak mengembalikan JSON yang valid di badan respons. Anda mengatakan kepadanya bahwa Anda sudah melihat metode itu, dan Anda percaya hal yang sama yang menyebabkannya mengembalikan kode keluar yang buruk juga menyebabkannya mengembalikan sesuatu yang bukan JSON yang valid, dan lebih mirip jejak jejak pengecualian.

Anda kembali bekerja, tetapi kemudian Jim dari QA tiba, mengatakan bahwa metode pengujian keempat gagal dan tidak ada kunci X dalam respons ...

Anda bahkan tidak dapat mencari alasannya karena sulit untuk melihat kode ketika Anda tidak memiliki layar komputer. Jika Jim cukup cepat dia bisa mengelak pada waktunya ...

Email dari server pengujian lebih mudah untuk diberhentikan, tetapi tetap - tidakkah Anda lebih suka diberitahu saja SEKALI ada sesuatu yang salah dengan metode pengujian, dan lihat sendiri log pengujian yang relevan?

Idan Arye
sumber
3

Jika Anda dapat dengan aman berasumsi bahwa membuat permintaan server dengan parameter yang sama akan selalu sama, metode B hampir tidak ada gunanya - mengapa Anda harus memanggil empat kali metode yang sama untuk mendapatkan data respons yang sama empat kali ketika satu panggilan sudah cukup?

Dan jika Anda tidak dapat dengan aman menganggap ini dan ingin menjadikannya bagian dari tes, Anda mungkin lebih baik menjalankan tes A beberapa kali.

Satu-satunya situasi hipotetis yang saya lihat di mana B mungkin memiliki manfaat adalah ketika kerangka kerja pengujian Anda hanya memungkinkan metode pengujian eksplisit untuk dinyalakan dan dimatikan, dan Anda mengharapkan perlunya melakukan ini untuk setiap langkah pengujian Anda.

Alternatif C tampaknya menggabungkan A dengan satu manfaat yang saya sebutkan di atas untuk B. Jika kerangka kerja pengujian Anda memungkinkan kode Anda disusun dengan mudah seperti itu, tanpa banyak overhead di atas B, ini adalah pendekatan yang layak. Namun, ini menambahkan beberapa kompleksitas tambahan ke A, jadi saya hanya akan menggunakannya jika saya ingin mengaktifkan dan menonaktifkan tes individual, jika tidak menerapkan prinsip YAGNI dan tetap menggunakan solusi yang paling sederhana (A).

TLDR: mulai dengan A jika Anda yakin Anda selalu ingin semua pernyataan dijalankan dalam satu tes, refactor ke C jika Anda melihat Anda perlu memiliki kontrol yang lebih mudah dari luar tentang masing-masing pernyataan.

Doc Brown
sumber
0

Seperti kode apa pun, hindari pengoptimalan prematur. Pertama, tulis tes Anda sehingga mudah dibaca dan mudah dipelihara. Ketika tes mulai terlalu lambat maka optimalkan. Dalam contoh Anda yang cukup sederhana, A dan B akan mudah dibaca dan dipelihara, jadi pilih yang mana yang Anda inginkan hingga semuanya menjadi terlalu lambat (struktur B) atau terlalu rumit (struktur A).

Jika server Anda tidak memiliki kewarganegaraan maka Anda dapat mengoptimalkan dengan membandingkan respons aktual dengan respons yang diharapkan untuk memeriksa seluruh pesan sekaligus. Jelas itu akan mengorbankan keterbacaan.

Jika server Anda statefull dan Anda perlu membuat beberapa panggilan api lambat untuk mendapatkan server dalam keadaan untuk tes maka Anda untuk mengambil pendekatan yang berbeda atau tes Anda mungkin membutuhkan beberapa menit untuk berjalan. Misalnya Anda bisa menjalankan pembaruan basis data untuk menyuntikkan data ke dalam basis data pengujian sehingga Anda bisa dengan cepat mendapatkan objek dalam kondisi yang sesuai untuk pengujian. Tes ini cepat dan mudah dibaca tetapi lebih sulit untuk dipertahankan. Atau Anda mungkin dapat menulis fasad di depan api sehingga beberapa panggilan api menjadi panggilan api tunggal yang lebih cocok dengan proses bisnis yang Anda uji.

Matt Helliwell
sumber
0

Tes tidak boleh berbagi hal-hal - mulai dari awal Anda menghindari pengaruh satu tes pada yang lain. Ini juga membuat Anda dapat menjalankan tes dalam urutan acak.
Jadi cara C seharusnya tidak diterima.


Saat menulis kode apa pun (atau mungkin bahkan membuat yang lain), selalu bertanya pada diri sendiri: "mengapa ada praktik seperti itu?"
Mengapa kami mengatakan bahwa harus ada tes yang berbeda untuk semuanya?

Ada dua kasus ketika Anda membutuhkan ini:

  1. ketika Anda tidak dapat mengandalkan "setiap langkah pengujian hanya dapat berhasil jika semua sebelumnya berhasil"
  2. ketika tes Anda tidak memiliki pesan yang tegas

Ada dua alasan mengapa Anda menghadapi kasus ini:

  1. "setiap langkah pengujian hanya dapat berhasil jika semua sebelumnya berhasil" benar-benar tidak berlaku untuk fitur produk Anda
  2. Anda tidak memiliki cukup pengetahuan tentang produk karena kurangnya pengalaman atau waktu, atau kompleksitas produk yang luar biasa

Jika Anda untuk beberapa alasan tidak dapat menyatakan setidaknya satu dari alasan ini untuk memiliki tempat hanya membabi buta mengambil struktur B .


Jika tidak (saya harap Anda dapatkan di sini) yang Anda pilih A .


Anda juga dapat mengajukan pertanyaan ini di situs Jaminan Kualitas & Pengujian Situs Stackexchange.

Nakilon
sumber