Advertisement
  1. Code
  2. Tools & Tips

Tips untuk Menghindari Tes UI yang Rapuh

by
Difficulty:IntermediateLength:LongLanguages:

Indonesian (Bahasa Indonesia) translation by Yusuf Samin (you can also view the original English article)

Dalam artikel terakhir saya berbicara tentang beberapa ide dan pola, seperti pola Page Object, yang membantu menulis tes UI yang dapat dipertahankan. Dalam artikel ini kita akan membahas beberapa topik lanjutan yang dapat membantu Anda menulis tes yang lebih kuat, dan memecahkan masalah ketika gagal:

  • Kami membahas mengapa menambahkan penundaan tetap pada tes UI adalah ide yang buruk dan bagaimana Anda dapat menyingkirkannya.
  • Kerangka otomatisasi browser menargetkan elemen UI menggunakan selector dan sangat penting untuk menggunakan selector yang baik untuk menghindari tes rapuh. Jadi saya memberi Anda beberapa saran tentang memilih penyeleksi yang tepat dan elemen penargetan secara langsung bila memungkinkan.
  • Tes UI gagal lebih sering daripada jenis tes lainnya, jadi bagaimana kita bisa men-debug tes UI yang rusak dan mencari tahu apa yang menyebabkan kegagalan? Di bagian ini saya menunjukkan kepada Anda bagaimana Anda dapat menangkap screenshot dan sumber HTML halaman saat tes UI gagal sehingga Anda dapat menyelidikinya dengan lebih mudah.

Saya akan menggunakan Selenium untuk topik otomatisasi browser yang dibahas dalam artikel ini.

Sama seperti artikel sebelumnya, konsep dan solusi yang dibahas dalam artikel ini dapat diterapkan terlepas dari bahasa dan kerangka kerja UI yang Anda gunakan. Sebelum melangkah lebih jauh silakan baca artikel sebelumnya karena saya akan merujuknya dan kode sampelnya beberapa kali. Jangan khawatir; Saya akan menunggu disini.


Jangan Tambahkan Penundaan ke Tes Anda

Menambahkan Thread.Sleep (atau umumnya penundaan) terasa seperti hack yang tak terhindarkan ketika datang ke pengujian UI. Anda memiliki tes yang gagal sebentar-sebentar dan setelah beberapa penyelidikan Anda melacaknya kembali ke penundaan sesekali dalam respons; Misalnya, Anda menavigasi ke halaman dan mencari atau menegaskan sesuatu sebelum halaman tersebut dimuat penuh dan kerangka kerja otomatisasi browser Anda mengeluarkan exception yang menunjukkan elemen tidak ada. Banyak hal yang dapat berkontribusi pada keterlambatan ini. Sebagai contoh:

  • Server web, basis data dan/atau jaringan kelebihan beban dan sibuk dengan permintaan lainnya.
  • Halaman yang diuji lambat karena memuat banyak data dan/atau meminta banyak tabel.
  • Anda sedang menunggu beberapa peristiwa terjadi pada halaman yang membutuhkan waktu.

Atau mencapur dari ini dan masalah lainnya.

Katakanlah Anda memiliki halaman yang biasanya membutuhkan waktu kurang dari satu detik untuk memuat tetapi tes yang dijalankan gagal sesekali karena kelambatan tanggapan. Anda punya beberapa pilihan:

  • Anda tidak menambahkan penundaan: dalam hal ini pengujian yang mengenai halaman itu terkadang akan gagal yang mengurangi kepercayaan Anda pada pengujian.
  • Anda menambahkan penundaan satu detik ke tes yang memukul halaman itu: dalam hal ini semua tes itu akan selalu memakan waktu satu detik lebih lama, bahkan ketika halaman memuat cepat, tetapi bahkan kemudian tes tidak dijamin lulus sebagai halaman terkadang membutuhkan waktu lebih lama dari satu detik untuk memuat.
  • Anda mungkin memutuskan untuk menambahkan jeda beberapa detik: ini memastikan halaman tersebut selalu selalu dimuat, tetapi sekarang tes UI Anda berlangsung lebih lama dan lebih lama.

Anda tahu, tidak ada kemenangan dengan penundaan semaunya: Anda bisa mendapatkan test suite yang lambat atau rapuh. Di sini saya akan menunjukkan kepada Anda bagaimana menghindari memasukkan penundaan yang tetap dalam pengujian Anda. Kami akan membahas dua jenis penundaan yang harus mencakup hampir semua kasus yang harus Anda tangani: menambah penundaan global dan menunggu sesuatu terjadi.

Menambahkan Penundaan Global

Jika semua halaman Anda memuat waktu yang sama untuk memuat, yang lebih lama dari yang diharapkan, maka sebagian besar pengujian akan gagal karena respons yang tidak tepat waktu. Dalam kasus seperti ini, Anda dapat menggunakan Penungguan Implisit:

Penungguan Implisit adalah memberi tahu WebDriver untuk melakukan polling DOM selama waktu tertentu ketika mencoba menemukan elemen atau elemen jika tidak segera tersedia. Pengaturan default adalah 0. Setelah diatur, Penungguan implisit diatur selama umur instance objek WebDriver.

Ini adalah bagaimana Anda mengatur Penungguan implisit:

Dengan cara ini Anda memberi tahu Selenium untuk menunggu hingga 5 detik ketika mencoba menemukan elemen atau berinteraksi dengan halaman. Jadi sekarang Anda dapat menulis:

dari pada:

Manfaat dari pendekatan ini adalah bahwa FindElement akan kembali segera setelah menemukan elemen dan tidak menunggu selama 5 detik saat elemen tersedia lebih cepat.

Setelah penungguan secara implisit diatur pada instance WebDriver Anda, itu berlaku untuk semua tindakan pada driver; sehingga Anda dapat menyingkirkan banyak Thread.Sleep di kode Anda.

5 detik adalah penantian yang saya buat untuk artikel ini - Anda harus menemukan Penungguan implisit optimal untuk aplikasi Anda dan Anda harus membuatnya menunggu sesingkat mungkin. Dari dokumentasi API:

Meningkatkan waktu Penungguan implisit harus digunakan secara bijaksana karena akan memiliki efek buruk pada waktu uji coba, terutama bila digunakan dengan strategi lokasi yang lebih lambat seperti XPath.

Bahkan jika Anda tidak menggunakan XPath, penungguan lama secara implisit memperlambat tes Anda, terutama ketika beberapa tes benar-benar gagal, karena driver web akan menunggu lama sebelum waktunya habis dan melempar exception.

Menunggu Peristiwa/Perubahan Eksplisit

Menggunakan penungguan secara implisit adalah cara yang bagus untuk menghilangkan banyak keterlambatan dalam kode Anda; tetapi Anda masih akan menemukan diri Anda dalam situasi di mana Anda perlu menambahkan beberapa penundaan tetap dalam kode Anda karena Anda sedang menunggu sesuatu terjadi: halaman lebih lambat dari semua halaman lain dan Anda harus menunggu lebih lama, Anda menunggu panggilan AJAX untuk menyelesaikan atau elemen muncul atau menghilang dari halaman dll. Di sinilah Anda perlu penungguan secara eksplisit.

Penungguan eksplisit

Jadi Anda telah menetapkan waktu tunggu implisit ke 5 detik dan itu berfungsi untuk banyak tes Anda; tetapi masih ada beberapa halaman yang kadang-kadang membutuhkan waktu lebih dari 5 detik untuk memuat dan mengakibatkan kegagalan tes.

Sebagai catatan tambahan, Anda harus menyelidiki mengapa suatu halaman butuh waktu lebih dulu, sebelum mencoba memperbaiki tes yang rusak dengan membuatnya menunggu lebih lama. Mungkin ada masalah kinerja pada halaman yang mengarah ke tes merah dalam hal ini Anda harus memperbaiki halaman, bukan tes.

Dalam hal halaman yang lambat, Anda dapat mengganti penundaan yang sudah diperbaiki dengan Penungguan Eksplisit:

Penungguan eksplisit adalah kode yang Anda tentukan untuk menunggu kondisi tertentu terjadi sebelum melanjutkan lebih jauh dalam kode.

Anda dapat menerapkan penungguan eksplisit menggunakan kelas WebDriverWaitWebDriverWait tinggal di assembly WebDriver.Support dan dapat diinstal menggunakan nuget Selenium.Support:

Berikut adalah contoh bagaimana Anda dapat menggunakan WebDriverWait dalam pengujian Anda:

Kami memberi tahu Selenium bahwa kami ingin menunggu laman/elemen ini hingga 10 detik.

Anda mungkin memiliki beberapa halaman yang membutuhkan waktu lebih lama daripada default implisit Anda dan itu bukan praktik pengkodean yang baik untuk terus mengulangi kode ini di mana-mana. Lagipula Kode Uji Adalah Kode. Sebagai gantinya, Anda dapat mengekstrak ini ke dalam metode dan menggunakannya dari pengujian Anda:

Kemudian Anda dapat menggunakan metode ini sebagai:

Ini adalah contoh yang dibuat untuk menunjukkan seperti apa metode yang berpotensi terlihat dan bagaimana itu dapat digunakan. Idealnya Anda akan memindahkan semua interaksi halaman ke objek halaman Anda.

Contoh Penungguan Eksplisit Alternatif

Mari kita lihat contoh lain dari penungguan eksplisit. Kadang-kadang halaman sudah dimuat penuh tetapi elemen belum ada di sana karena nanti dimuat sebagai hasil dari permintaan AJAX. Mungkin itu bukan elemen yang Anda tunggu tetapi hanya ingin menunggu interaksi AJAX selesai sebelum Anda dapat membuat assertion, katakan dalam database. Sekali lagi ini adalah tempat sebagian besar pengembang menggunakan Thread.Sleep untuk memastikan bahwa, misalnya, panggilan AJAX dilakukan dan record sekarang ada di database sebelum mereka melanjutkan ke baris tes berikutnya. Ini dapat dengan mudah diperbaiki menggunakan eksekusi JavaScript!

Sebagian besar kerangka kerja otomatisasi browser memungkinkan Anda untuk menjalankan JavaScript pada sesi aktif, dan Selenium tidak terkecuali. Di Selenium ada interface yang disebut IJavaScriptExecutor dengan dua metode:

Interface ini diimplementasikan oleh RemoteWebDriver yang merupakan kelas dasar untuk semua implementasi driver web. Jadi pada contoh driver web Anda, Anda dapat memanggil ExecuteScript untuk menjalankan skrip JavaScript. Berikut adalah metode yang dapat Anda gunakan untuk menunggu semua panggilan AJAX selesai (dengan asumsi Anda menggunakan jQuery):

Menggabungkan ExecuteScript dengan WebDriverWait dan Anda dapat menyingkirkan Thread.Sleep yang ditambahkan untuk panggilan AJAX.

jQuery.active mengembalikan jumlah panggilan AJAX aktif yang diprakarsai oleh jQuery; jadi ketika nol, tidak ada panggilan AJAX yang sedang berlangsung. Metode ini jelas hanya berfungsi jika semua permintaan AJAX dimulai oleh jQuery. Jika Anda menggunakan perpustakaan JavaScript lain untuk komunikasi AJAX, Anda harus membaca dokumentasi API untuk metode yang setara atau melacak sendiri panggilan AJAX.

ExpectedCondition

Dengan tunggu eksplisit, Anda dapat menetapkan kondisi dan menunggu hingga terpenuhi atau batas waktu habis. Kami melihat bagaimana kami dapat memeriksa panggilan AJAX untuk diselesaikan - contoh lain sedang memeriksa visibilitas suatu elemen. Sama seperti cek AJAX, Anda bisa menulis suatu kondisi yang memeriksa visibilitas suatu elemen; tetapi ada solusi yang lebih mudah untuk itu yang disebut ExpectedCondition.

Dari Selenium dokumentasi:

Ada beberapa kondisi umum yang sering dijumpai ketika mengotomatisasi browser web.

Jika Anda menggunakan Java, Anda beruntung karena kelas ExpectedCondition di Java cukup luas dan memiliki banyak metode yang bermanfaat. Anda dapat menemukan dokumentasinya di sini.

Pengembang .Net tidak seberuntung ini. Masih ada kelas ExpectedConditions di assembly WebDriver.Support (didokumentasikan di sini) tetapi sangat minim:

Anda dapat menggunakan kelas ini dalam kombinasi dengan WebDriverWait:

Seperti yang dapat Anda lihat dari signature kelas di atas, Anda dapat memeriksa judul atau bagiannya dan untuk keberadaan dan visibilitas elemen menggunakan ExpectedCondition. Dukungan out of the box di .Net mungkin sangat minim; tetapi kelas ini tidak lain hanyalah pembungkus beberapa kondisi sederhana. Anda dapat dengan mudah mengimplementasikan kondisi umum lainnya di kelas dan menggunakannya dengan WebDriverWait dari skrip pengujian Anda.

FluentWait

Permata lain hanya untuk pengembang Java adalah FluentWait. Dari halaman dokumentasi, FluentWait adalah

Implementasi antarmuka Tunggu yang mungkin memiliki interval waktu habis dan jajak pendapatnya dikonfigurasi dengan cepat. Setiap instance FluentWait menentukan jumlah waktu maksimum untuk menunggu suatu kondisi, serta frekuensi yang digunakan untuk memeriksa kondisi tersebut. Selain itu, pengguna dapat mengonfigurasi penungguan untuk mengabaikan jenis exception tertentu saat menunggu, seperti NoSuchElementExceptions saat mencari elemen di halaman.

Dalam contoh berikut, kami mencoba menemukan elemen dengan id foo di halaman pemungutan suara setiap lima detik hingga 30 detik:

Ada dua hal luar biasa tentang FluentWait: pertama memungkinkan Anda untuk menentukan interval pemungutan suara yang dapat meningkatkan kinerja tes Anda dan kedua memungkinkan Anda untuk mengabaikan exception yang tidak anda minati.

FluentWait cukup mengagumkan dan akan keren jika yang setara ada di .Net juga. Yang mengatakan itu tidak terlalu sulit untuk mengimplementasikannya menggunakan WebDriverWait.


Memilih Selector Tepat

Anda memiliki Page Objecs Anda di tempat, memiliki kode tes DRY yang dapat dipelihara yang bagus, dan juga menghindari penundaan tetap dalam pengujian Anda; tetapi tes Anda masih gagal!

UI biasanya merupakan bagian yang paling sering diubah dari aplikasi tipikal: kadang-kadang Anda memindahkan elemen di sekitar halaman untuk mengubah desain halaman dan kadang-kadang perubahan struktur halaman berdasarkan persyaratan. Perubahan pada tata letak dan desain halaman ini dapat menyebabkan banyak tes yang rusak jika Anda tidak memilih selector Anda dengan bijak.

Jangan gunakan selector tidak jelas dan jangan mengandalkan struktur halaman Anda.

Sering kali saya ditanya apakah boleh menambahkan ID ke elemen pada halaman hanya untuk pengujian, dan jawabannya adalah ya. Untuk membuat unit kode kami dapat diuji, kami membuat banyak perubahan seperti menambahkan intrface dan menggunakan Dependency Injection. Kode Uji Adalah Kode. Lakukan apa yang diperlukan untuk mendukung tes Anda.

Katakanlah kita memiliki halaman dengan daftar berikut:

Dalam salah satu tes saya, saya ingin mengklik album "Let There Be Rock". Saya akan meminta masalah jika saya menggunakan selector berikut:

Jika memungkinkan Anda harus menambahkan ID ke elemen dan menargetkannya secara langsung dan tanpa bergantung pada elemen di sekitarnya. Jadi saya akan membuat perubahan kecil ke daftar:

Saya telah menambahkan atribut id ke anchor berdasarkan id album unik sehingga kami dapat menargetkan tautan langsung tanpa harus melalui elemen ul dan li. Jadi sekarang saya bisa mengganti selector rapuh dengan By.Id ("album-35") yang dijamin akan berfungsi selama album itu ada di halaman, yang omong-omong juga merupakan assertion yang bagus juga. Untuk membuat selector itu saya jelas harus memiliki akses ke id album dari kode tes.

Namun, tidak selalu mungkin untuk menambahkan id unik ke elemen, seperti baris dalam grid atau elemen dalam daftar. Dalam kasus seperti ini, Anda dapat menggunakan kelas CSS dan atribut data HTML untuk melampirkan properti yang dapat dilacak ke elemen Anda untuk selector yang lebih mudah. Misalnya, jika Anda memiliki dua daftar album di halaman Anda, satu sebagai hasil pencarian pengguna dan satu lagi untuk album yang disarankan berdasarkan pembelian pengguna sebelumnya, Anda dapat membedakannya menggunakan kelas CSS pada elemen ul, bahkan jika kelas itu tidak digunakan untuk menata daftar:

Jika Anda memilih untuk tidak menggunakan kelas CSS yang tidak digunakan, Anda bisa menggunakan atribut data HTML dan mengubah daftar menjadi:

dan:


Debugging Tes UI

Salah satu alasan utama pengujian UI gagal adalah bahwa elemen atau teks tidak ditemukan pada halaman. Terkadang ini terjadi karena Anda mendarat di halaman yang salah karena kesalahan navigasi, atau perubahan navigasi halaman di situs web Anda, atau kesalahan validasi. Lain waktu bisa karena halaman yang hilang atau kesalahan server.

Terlepas dari apa yang menyebabkan kesalahan dan apakah Anda mendapatkannya di log server CI Anda atau di konsol pengujian desktop Anda, NoSuchElementException (atau sejenisnya) tidak cukup berguna untuk mencari tahu apa yang salah, bukan? Jadi, ketika pengujian Anda gagal, satu-satunya cara untuk memecahkan masalah kesalahan adalah dengan menjalankannya lagi dan melihatnya gagal. Ada beberapa trik yang berpotensi menyelamatkan Anda dari menjalankan kembali tes UI lambat Anda untuk pemecahan masalah. Salah satu solusi untuk ini adalah menangkap screenshot setiap kali tes gagal sehingga kami dapat merujuk kembali kepadanya nanti.

Ada interface di Selenium yang disebut ITakesScreenshot:

Interface ini diimplementasikan oleh kelas driver web dan dapat digunakan seperti ini:

Dengan cara ini ketika tes gagal karena Anda berada di halaman yang salah, Anda dapat dengan cepat mengetahuinya dengan memeriksa screenshot yang diambil.

Bahkan menangkap screenshots tidak selalu cukup. Misalnya, Anda mungkin melihat elemen yang Anda harapkan di halaman tetapi tes masih gagal mengatakan itu tidak menemukannya, mungkin karena selector yang salah yang mengarah ke pencarian elemen yang gagal. Jadi, alih-alih (atau melengkapi) screenshot, Anda juga bisa menangkap sumber halaman sebagai html. Ada properti PageSource pada interface IWebDriver (yang diimplementasikan oleh semua driver web):

Sama seperti yang kami lakukan dengan ITakesScreenshot, Anda dapat menerapkan metode yang mengambil sumber halaman dan meneruskannya ke file untuk diperiksa nanti:

Anda tidak benar-benar ingin mengambil screenshots dan sumber halaman dari semua halaman yang Anda kunjungi dan untuk pengujian yang lulus; jika tidak, Anda harus melalui ribuan dari mereka ketika ada sesuatu yang salah. Daripada, Anda hanya boleh menangkapnya saat tes gagal atau sebaliknya saat Anda membutuhkan informasi lebih lanjut untuk pemecahan masalah. Untuk menghindari mencemari kode dengan blok try-catch yang terlalu banyak dan untuk menghindari duplikasi kode Anda harus meletakkan semua pencarian elemen dan pernyataan Anda dalam satu kelas dan membungkusnya dengan try-catch dan kemudian menangkap screenshot dan/atau sumber halaman di blok catch . Berikut adalah sedikit kode yang dapat Anda gunakan untuk mengeksekusi tindakan terhadap suatu elemen:

Kelas Capturer dapat diimplementasikan sebagai:

Implementasi ini tetap menggunakan screenshot dan sumber HTML dalam folder bernama FailedTests di sebelah tess, tetapi Anda dapat memodifikasinya jika Anda menginginkan perilaku yang berbeda.

Meskipun saya hanya menunjukkan metode khusus untuk Selenium, API serupa ada di semua kerangka kerja otomasi yang saya tahu dan dapat dengan mudah digunakan.


Kesimpulan

Pada artikel ini kita berbicara tentang beberapa tips dan trik pengujian UI. Kami membahas bagaimana Anda dapat menghindari rangkaian uji UI yang rapuh dan lambat dengan menghindari fixed delay dalam pengujian Anda. Kami kemudian mendiskusikan cara menghindari selector dan pengujian yang rapuh dengan memilih selector dengan bijak dan juga cara men-debug tes UI Anda saat gagal.

Sebagian besar kode yang ditampilkan dalam artikel ini dapat ditemukan di repositori sampel MvcMusicStore yang kita lihat di artikel terakhir. Perlu juga dicatat bahwa banyak kode di MvcMusicStore dipinjam dari basis kode Seleno, jadi jika Anda ingin melihat banyak trik keren, Anda mungkin ingin memeriksa Seleno. Penafian: Saya adalah salah satu pendiri organisasi TestStack dan kontributor di Seleno.

Saya harap apa yang telah kita bahas dalam artikel ini membantu Anda dalam upaya pengujian UI Anda.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.