Kunci untuk bergerak cepat adalah kepercayaan diri untuk melakukan perubahan.

Keyakinan untuk melakukan perubahan bergantung pada cakupan tes.

Sejak kami mengetahuinya, pengujian otomatis menjadi penting. Hal ini menyebabkan adopsi cuplikan memulaisecara massal.

Namun, memulai saja tidak cukup.

Apa yang salah dengan cuplikan awal?

Sebagian besar contoh yang tersedia bertujuan untuk memulainya dengan cepat. Hal ini berlaku untuk "stackoverflow", "codewhisperer", "copilot", "Bard", dan "ChatGPT". Bahkan tutorial kerangka pengujian juga ikut disalahkan.

Mengapa?

  1. Mereka bertujuan untuk mendapatkan kesamaan pembaca yang paling rendah. Karena itu, mereka melewatkan detail profesional.
  2. Mereka menunda bagian curam dari kurva pembelajaran. Anda akan menemuinya hanya setelah Anda terpikat pada kerangka mereka.
  3. Ada pendapat yang berlawanan tentang praktik dan gaya terbaik. Jadi tutorialnya mencoba untuk tetap tidak beropini, atau menampilkan opini mereka sebagai fakta.
    Kedua cara tersebut menghindari diskusi dan pemikiran yang seharusnya menginspirasi.
  4. Banyak pengoptimalan bergantung pada kemampuan tim, budaya, dan kasus nyata.

Hasilnya biasanya berhasil, tetapi merupakan hasil terbaik bagi siswa.

Bagian selanjutnya menjelaskan jebakan budaya kita, mengapabudaya itu rusak dan apa memimpinnya.
Untuk bagaimanadan contoh kode— lewati "di sini".

Realitas yang Hilang

Kita menjalani kenyataan terburu-buru mencapai garis akhir dari suatu nilai yang diberikan kepada pelanggan. Kita lupa bahwa garis finis ini adalah putaran sewenang-wenang dalam perlombaan yang lebih panjang.

Kenyataan yang kami lewatkan adalah:

Basis kode dibuat satu kali namun diuji terus menerussepanjang masa pakainya.

T.T.R. — Saatnya Pemulihan

Basis kode pasti akan berkembang dan Pengujian pasti akan gagal.
Namun berapa lama waktu yang dibutuhkan untuk pulih dari pengujian yang gagal?

Dalam hal ini, sebagian besar pekerjaan kita bukanlah menulis kode baru, namun memasukkan kode yang sudah ada. Kita perlu menguraikan kode produksi dan pengujian untuk menilai keduanya:

  • Apakah kode pengujian menjaga spesifikasi valid yang harus ditegakkan?
    — atau —
  • Apakah spesifikasi baru membuat spesifikasi lama menjadi usang?

Semakin sedikit penguraian yang Anda perlukan — semakin baik TTR Anda. Ada kenyataan yang lebih baik lagi:

Bagaimana jika tes tersebut dapat mengkomunikasikan dengan tepat persyaratan apa yang mereka jaga?

Bagaimana jika hanya hasil pengujian yang perlu Anda ketahui apa yang harus Anda perbaiki tanpa menguraikan kode apa pun?

Bagaimana jika hal tersebut dapat memberikan Anda kejelasan yang sama bahkan 6 bulan kemudian?

Nah, Anda bisa melewatkan bagian pemulihan yang paling membuat frustrasi itu...

Kunci Budaya

Industri kita terus-menerus berada dalam kondisi kekurangan pengalaman. Periksa tautan Paman Bob menjelaskannya. Dengan demikian, budaya gagal untuk disebarkan.

Artinya, banyak dari kita yang perlu menciptakan roda yang sama berulang kali. Dan fakta bahwa kami mendapatkan hasil yang serupa berarti itu adalah jawaban yang benar.

Budaya yang baik memupuk perbaikan berkelanjutan.

Memperlakukan pengujian yang gagal seperti pemadaman listrik adalah elemen budaya lainnya.
Mengoptimalkan TTR adalah elemen budaya.

Tapi bagaimana menuju ke sana?

Faktor Utama

Apa kesamaan antara notifikasi tentang penghentian layanan dan notifikasi tentang build yang gagal?

  • Keduanya merupakan notifikasi yang mengganggu alur kerja Anda dan harus ditangani.
  • Keduanya kemungkinan akan membantu Anda memulai kursus pemecahan masalah untuk mengurangi konteksnya.
  • Setiap menit yang Anda habiskan untuk salah satu dari keduanya sama saja dengan memadamkan api dan bukannya membuat kemajuan.

Tentu saja, apinya tidak sama besarnya, tetapi pada intinya - perasaan buruk yang sama seperti pemborosan dan miskomunikasi.

Keajaiban terjadi ketika tim memutuskan untuk bertindak berdasarkan kesamaan antara pengujian yang gagal dan penghentian waktu henti.

Dan pelajarannya adalah

Saat Anda memperlakukan pengujian yang gagal seperti pemadaman listrik, pengoptimalan TTR menghasilkan beberapa kesimpulan:

  1. Aspirasikan keluaran pengujian agar cukup bertele-tele sehingga Anda tidak perlu membaca kode pengujian, yaitu melontarkan semua konteks yang Anda perlukan dengan kesalahan.
  2. Jangan berasumsi pengembangnya mengetahuinya. Ambil langkah ekstra untuk mendeskripsikan kasus penggunaan dan konteksnya.
  3. Alihkan beban kognitif dari perancah dan instrumentasi.
  4. Fokuskan beban kognitif pada detail bermakna dari kasus uji.

Mari kita mulai dari kasus terburuk, dan memperbaikinya sedikit demi sedikit.

Level (-5) — permulaan yang naif

Sayangnya, sebagai konsultan saya masih melihat rangkaian pengujian dengan semangat ini:

const myModule = ... //require or import the System-Under-Test

it("should work", async () => {
  await setup...;
  await step1(...);
  expect(…)... .
  await step2(...);
  expect(…)... .
  await step3(...);
  expect(…)... .

  // and a load more of those in the same function
});

Ini adalah batas minimum yang dapat menghentikan penerapan kode yang salah.

Untuk bentuk postingan ini yang paling disempurnakan — lewati di sini.

Ini adalah dunia pengujian yang setara dengan kode yang tidak terorganisir, tidak diberi nama dengan baik, tidak berarsitektur, sangat bertumpuk kasus, penuh dengan salinan-tempel dan tanpa memperhatikan isolasi atau kekhawatiran. Banyak yang akan dengan enggan menyebutnya sebagai skrip, seolah-olah skrip bukanlah kode (sangat menipu diri sendiri…)!

Namun, terlalu banyak tim yang tidak memerlukan kode pengujian mereka lebih banyak.

Di akhir postingan ini, Anda seharusnya sudah bisa mengetahui betapa mengerikannya hal itu. Tentu saja, ini lebih baik daripada tidak melakukan tes sama sekali, namun, dalam laju industri kita, hal ini akan segera menghambat kemajuan Anda.

Apa yang salah dengan level (-5)?

Beberapa hal.

  1. Ini memberi penghormatan kepada arahan BDD untuk “ikuti kata-kata API dalam bahasa Inggris“. Namun ia melakukannya dengan cara yang tidak memberikan informasi apa pun tentang kasus uji atau skenarionya.
  2. Jika ada langkah yang gagal — seluruh skenario terhenti dan langkah berikutnya tidak dapat dijalankan.
    (ℹ️) TerkadangSaya melihat try-catchdengan upaya pembersihan. Ini tidak jauh lebih baik, karena Anda masih harus menebus atau mengulang kembali kesalahan yang seharusnya dihasilkan oleh tes tersebut. Hal ini membuat Anda bekerja untuk peserta ujian alih-alih membuatnya bekerja untuk Anda.
  3. Ketika skenario gagal, semua indikasi yang Anda dapatkan adalah kesalahan. Jika kesalahannya masih mentah - biasanya kesalahan tersebut bersifat samar dan umum serta tidak memberikan banyak informasi berguna.
  4. Jika beberapa langkah dalam skenario dapat menimbulkan kesalahan serupa, hal ini akan membingungkan. Hal ini membuat sulit untuk mencatat titik kegagalannya.
    (ℹ️) TerkadangSaya mengerti consul.log panggilan yang mencoba membantu mengidentifikasi titik dalam alur pengujian. Namun hal ini lagi-lagi berfungsi untuk test runner dan perpustakaan pernyataan, bukan membiarkannya bekerja untuk Anda.
  5. Ketika terjadi kegagalan — Anda tidak tahu di mana pelakunya. Apakah masalahnya ada pada kode pengujian? Yaitu. apakah pengujian gagal mengatur, berinteraksi, atau membersihkan setelah S.U.T (System-Under-Test)?
    Atau karena S.U.T gagal, yaitu perubahan yang mengganggu dalam kode produksi?
    (ℹ️) TerkadangSaya melihat komentar //arrange atau //setup dan //cleanup atau //teardown. Tapi ini adalah komentar yang terlihat di kode pengujian, yang tujuannya adalah untuk menghilangkan kita dari membaca kode pengujian.

Jika terjadi kegagalan, kemungkinan besar Anda akan menghabiskan waktu yang berharga untuk beralih antara kode pengujian dan kode produksi, mencoba memahami semua omong kosong itu bahkan sebelum Anda dapat menilai mana di antara keduanya yang benar.

Mengatasi semua “(ℹ️) terkadang” yang disebutkan di atas mungkin akan membawa Anda dari level (-5) ke level (-2), dan masih meninggalkan Anda jauh di belakang.

Struktur seperti itu gagal dalam wawancara kerja yang layak.

Level 0 — Menggunakan judul

Tingkat berikutnya yang bisa saya lihat adalah semangat berikut.

describe('my-module', () => {
  // async api_one(...) 
  it('should do this when called with ...', async () => { ...
  it('should do that when called after ...', async () => { ...
  it('should throw that error when ...', async () => { ...

  // async api_two(...)
  it('should do this when called with ...', async () => { ...
  it('should do that when called after ...', async () => { ...
  it('should throw that error when ...', async () => { ...

Banyak sekali contoh seperti ini di internet, dalam tutorial, dan pengujian paket open source yang sering dijadikan referensi.

Di sini kita berada dalam kondisi yang jauh lebih baik daripada cuplikan sebelumnya:

  • Itu terorganisir
  • Ada pemikiran yang jelas tentang matriks kasus
  • Ini adalah dasar untuk isolasi pengujian — kegagalan dalam satu pengujian tidak akan menghalangi jalannya kasus lainnya
  • Ketika tes mana pun gagal — penjelasan bahasa Inggris akan muncul di hasil tes dengan kesalahan penolakan.

Apa yang masih salah?

Pertama— Mulai dari yang kecil. Urutan teksnya terbalik.

Jika Anda melihat matriks kasus (atau tabel kebenaran apa pun) — kondisinya didahulukan. Dalam tatanan alami, Anda menetapkan prasyarat dan kemudian mengharapkan suatu perilaku. Anda tidak mengamati suatu perilaku dan kemudian mencocokkannya dengan prasyarat yang mendasarinya… Setidaknya pada tingkat manusia - bentuk itu membingungkan.

Dan bagaimana jika dalam kondisi serupa Anda ingin memvalidasi beberapa persyaratan? Haruskah Anda mengulangi ketentuan di setiap judulnya? Apakah Anda akan bertindak secara asinkron untuk memeriksa properti yang berbeda setiap kali?

Kedua— Ketika pengujian gagal, Anda masih harusmembaca kode pengujian.

Perpustakaan pernyataan populer seperti “harus”, “mengharapkan” atau “chai” mencoba meniru bahasa Inggris. Hal ini memungkinkan pembuat kode untuk menyampaikan informasi tentang pengujian dalam kode. Namun hal ini juga membawa ilusi bahwa Anda dapat melepaskan judul yang bagus, sehingga Anda harus membaca kode pengujian pada setiap kegagalan.

Kode pengujian masih berupa kode, dan kode cenderung memiliki rasio signal-to-noise yang buruk. Bahkan hal-hal yang mungkin tidak Anda anggap sebagai kebisingan memerlukan upaya kognitif.

Ketiga — bagian dibagi berdasarkan komentar, yang tidak dapat diakses oleh reporter spesifikasi.

Reporteradalah bagian yang digunakan oleh test runner untuk menampilkan hasil pada output pengujian. Kebanyakan reporter memberikan ringkasan kegagalan pada akhirnya.

Spec-reporter adalah reporter yang mencetak seluruh pohon kasus pengujian menggunakan deskripsi dan judul Anda, biasanya sebelum ringkasan kegagalan.
Ini menandai setiap tes di pohon dengan notasi lulus/gagal/lewati. Hal ini memungkinkan pembacaan narasi yang diceritakan oleh pohon pengujian Anda dan tempat terjadinya kegagalan.

Komentar tidak dapat diakses oleh reporter pengujian — membuat Anda kembali membaca kode pengujian.

Dengan disiplin tertentu, laporan ini dapat bertindak sebagai spesifikasi perangkat lunak. Yaitu. — dokumentasi yang dapat dibaca yang dihasilkan langsung dari kode pengujian Anda.

Reporter spesifikasi bekerja dengan baik dalam hubungannya dengan tes yang tertunda. Menggunakan pengujian yang tertunda berarti menambahkan judul spesifikasi tanpa menyediakan penangan pengujiannya. Hal ini membuat mereka muncul di pohon sebagai dilewati.
Hal ini berguna untuk menuliskan langsung ke suite semua kasus yang ingin Anda terapkan dan membahasnya nanti satu per satu.

Reporter spesifikasi adalah reporter default untuk mocha, yang dibangun untuk mengetuk, didukung oleh runner in node bawaan. Ia bekerja dengan "Jest" menggunakan "paket plugin".

(ℹ️) Ingatlah bahwa Anda tidak perlu menulis tes terlebih dahulu atau bekerja dengan TDD/BDD untuk menggunakan reporter spesifikasi. Jalankan reporter spesifikasi kapan pun Anda ingin melihat narasi apa yang disampaikan oleh pohon pengujian Anda :)

Terakhir— ada beberapa hal yang dapat Anda minta agar dilakukan oleh pelari penguji:

  1. jalankan pengaturan dan pembersihan untuk Anda.
  2. pastikan bahwa jika pengujian gagal, pembersihan akan tetap terjadi
  3. gagal dalam pengujian yang pengaturan atau pembersihannya gagal
  4. memberi tahu Anda tentang kesalahan jika pengujian gagal pada pengaturan atau selama pengujian itu sendiri.

Memperbaiki 4 masalah ini akan membawa Anda kelevel (4).

Level (4) — profesional dasar

describe('my-module', () => {
  context('when used in cased A…', () => {
    before(async () => { ... //case setup
    it('should fulfil requirement 1…', () => { ...
    it('should fulfil requirement 2…', () => { ...
    ...
    after(async () => { ...  //cleanup
  })
  context('when used in case B…', () => {
    before(async () => { ... //case setup
    it('should fulfil requirement 1…', () => { ...
    it('should fulfil requirement 2…', () => { ...
    ...
    after(async () => { ... //cleanup

Mocha BDD merekomendasikan api context untuk menjelaskan konteks kasus. Faktanya, ini adalah alias untuk describe. Jest hanya mendukung describe dan memungkinkan Anda menyusunnya seperti mocha, jadi menggunakan describe membuat keduanya seragam.

Tahapan Arrangedan Actdilakukan pada hook before asinkron — mis. menyuntikkan data pengujian, dan melakukan permintaan HTTP. Kemudian semua langkah Tegaskanberoperasi pada objek respons yang diperoleh, dan terjadi secara sinkron.

Rekap

Apa yang telah kita capai sejauh ini?

  1. Test-runner memastikan bahwa kode penyiapan & pembongkaran tetap berjalan bahkan ketika skenario gagal. Tanpa coba-coba, tanpa console.log. Pelari pengujian akan memberi tahu Anda pada setiap kegagalan, apa sebenarnya penangan yang gagal. Ini akan mencatat apakah itu adalah kait pengaturan/pembongkaran atau pengujian itu sendiri.
  2. Konteks dan kasus dikomunikasikan dengan judul yang akan dicetak untuk setiap tes yang gagal.
  3. Setiap konteks memiliki penutupannya sendiri dengan variabelnya sendiri. Anda dapat menggunakannya untuk menyimpan status yang relevan dengan kasus uji.

(ℹ️) mocha memungkinkan Anda mempertahankan status di this. Anda harus menulis semua penangan Anda sebagai fungsi jadul, bukan fungsi panah.
Secara pribadi, saya tidak menyukai penggunaan this dalam JavaScript dan ingin mempertahankan status saya pada anggota penutupan, tetapi Anda melakukannya…

Jalannya masih panjang. Ini belum setengah jalan.
Ini bukan postingan pertama tentang tes (berikut link ke satu, "dua", dan tiga). Mungkin ada lebih banyak bagian dalam seri ini.

Terus gimana?

Masih banyak lagi level yang perlu dinilai.
Misalnya:

  1. Anda bisa menguasai ejekan dengan mata-mata, dan rintisan.
    (ℹ️) Namun hati-hati jangan sampai tersesat dalam cakupan unit dan gagal dalam pengujian bahwa sistem bekerja secara keseluruhan.
  2. Anda dapat menggunakan pabrik uji kasus. Ini memungkinkan Anda mengekspresikan pengujian Anda dengan fokus tunggal pada masukan, keluaran, dan harapan. Jauh lebih baik daripada menyalin-menempelkan seluruh struktur dan meretas di dalamnya.
  3. Anda dapat mengatur perlengkapan data. Fasilitasi pengaturan dan pembersihannya, dan atur sebagai modul sehingga Anda dapat mengimpor kait pengaturan/pembongkarannya, dan mengimpor data yang dimasukkan itu sendiri. Hal ini memungkinkan Anda menggunakan dan membuat pernyataan terhadap entitas logis, bukan nilai yang di-hardcode dalam pengujian Anda.
  4. Anda dapat "membuat laporan cakupan" dan mengintegrasikan deteksi bau kode. Anda kemudian dapat menggunakan ratchet bergerak dari batangan berkualitas.

Sekarang giliran Anda yang mengajari saya:
- LMK: manakah yang harus saya bahas terlebih dahulu?
- Tunjukkan kepada saya di tepuk tangan antara 1 hingga 50 bagaimana Anda menyukai karya ini.
💙 Saya menghargai keterlibatan dan waktu Anda 💙

Terima kasih khusus kepada Yonatan Kra, orang baik yang pernah bekerja dengan saya di masa lalu yang videonya akhirnya mendorong saya kembali untuk duduk dan menulis semua ini.