Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. ASP.NET

Tes UI Otomatis yang Dapat Di Pelihara

by
Read Time:21 minsLanguages:

Indonesian (Bahasa Indonesia) translation by Yudha Zubair (you can also view the original English article)

Beberapa tahun yang lalu saya sangat skeptis tentang pengujian UI otomatis dan skeptisisme ini lahir dari beberapa upaya yang gagal. Saya akan menulis beberapa tes UI otomatis untuk aplikasi desktop atau web dan beberapa minggu kemudian saya akan mencabutnya dari basis kode karena biaya pemeliharaannya terlalu tinggi. Jadi saya berpikir bahwa pengujian UI itu sulit dan bahwa, meskipun memberikan banyak manfaat, yang terbaik adalah menjaganya tetap minimum dan hanya menguji alur kerja yang paling kompleks dalam suatu sistem melalui pengujian UI dan menyerahkan sisanya pada unit test. Saya ingat memberi tahu tim saya tentang piramida pengujian Mike Cohn, dan bahwa dalam sistem tipikal lebih dari 70% tes harus berupa tes unit, sekitar 5% tes UI dan tes integrasi lainnya.

Jadi saya pikir pengujian UI itu sulit dan itu, meskipun memberikan banyak manfaat, yang terbaik adalah menjaganya tetap minimum ...

Saya salah! Tentu, pengujian UI bisa sulit. Dibutuhkan sedikit waktu untuk menulis tes UI dengan benar. Mereka jauh lebih lambat dan lebih rapuh daripada tes unit karena mereka melewati batas kelas dan proses, mereka mengenai browser, melibatkan elemen UI (mis. HTML, JavaScript) yang terus berubah, mereka mengenai database, sistem file, dan layanan jaringan yang berpotensi. Jika ada bagian yang bergerak ini tidak bermain dengan baik Anda memiliki tes yang rusak; tapi itu juga keindahan dari tes UI: mereka menguji sistem Anda dari ujung ke ujung. Tidak ada tes lain yang memberi Anda cakupan yang menyeluruh atau menyeluruh. Tes UI otomatis, jika dilakukan dengan benar, bisa menjadi elemen terbaik dalam rangkaian regresi Anda.

Jadi, dalam beberapa proyek terakhir, tes UI saya telah membentuk lebih dari 80% tes saya! Saya juga harus menyebutkan bahwa sebagian besar proyek ini adalah aplikasi CRUD dengan logika bisnis yang tidak banyak dan mari kita hadapi itu - sebagian besar proyek perangkat lunak termasuk dalam kategori ini. Logika bisnis masih harus di unit test; tetapi sisa aplikasi dapat diuji secara menyeluruh melalui otomatisasi UI.


Pengujian UI Sudah Salah

Saya ingin menyentuh apa yang saya lakukan salah, yang juga tampaknya sangat khas di kalangan pengembang dan penguji yang dimulai dengan otomatisasi UI.

Jadi apa yang salah dan mengapa? Banyak tim memulai otomatisasi UI dengan perekam layar. Jika Anda melakukan otomatisasi web dengan Selenium, kemungkinan besar Anda menggunakan Selenium IDE. Dari beranda Selenium IDE:

Selenium-IDE (Integrated Development Environment) adalah alat yang Anda gunakan untuk mengembangkan kasus uji Selenium Anda.

Ini sebenarnya salah satu alasan pengujian UI berubah menjadi pengalaman yang mengerikan: Anda mengunduh dan menjalankan perekam layar dan menavigasi ke situs web Anda dan klik, klik, ketik, klik, ketik, tab, ketik, tab, ketik, tab, ketik, klik dan assert. Kemudian Anda memutar ulang rekaman dan itu berfungsi. Manis!! Jadi, Anda mengekspor tindakan sebagai skrip pengujian, memasukkannya ke dalam kode Anda, membungkusnya dalam pengujian dan menjalankan pengujian dan melihat browser menjadi hidup di depan mata Anda dan tes Anda berjalan dengan sangat lancar. Anda menjadi sangat bersemangat, membagikan temuan Anda dengan kolega Anda dan memamerkannya kepada atasan Anda dan mereka menjadi sangat bersemangat dan pergi: "Otomatiskan SEMUA HAL"

Seminggu kemudian dan Anda memiliki 10 tes UI otomatis dan semuanya tampak hebat. Kemudian bisnis meminta Anda untuk mengganti nama pengguna dengan alamat email karena telah menyebabkan beberapa kebingungan di antara pengguna, dan Anda melakukannya. Kemudian seperti programmer hebat lainnya Anda menjalankan UI test suite Anda, hanya untuk menemukan 90% dari tes Anda rusak karena untuk setiap tes Anda login pengguna dengan username dan nama bidang telah berubah dan Anda membutuhkan dua jam untuk mengganti semua referensi untuk username dalam tes Anda dengan email dan untuk mendapatkan tes hijau lagi. Hal yang sama terjadi berulang-ulang dan pada titik tertentu Anda menemukan diri Anda menghabiskan berjam-jam sehari memperbaiki tes yang rusak: tes yang tidak rusak karena ada yang salah dengan kode Anda; tetapi karena Anda mengubah nama bidang dalam basis data/model Anda atau Anda sedikit merestrukturisasi halaman Anda. Beberapa minggu kemudian Anda berhenti menjalankan tes Anda karena biaya perawatan yang sangat besar ini, dan Anda menyimpulkan bahwa pengujian UI payah.

Anda TIDAK boleh menggunakan Selenium IDE atau perekam layar lainnya untuk mengembangkan kasus pengujian Anda. Yang mengatakan, itu bukan perekam layar itu sendiri yang mengarah ke test suite rapuh; itu kode yang mereka hasilkan yang memiliki masalah perawatan yang melekat. Banyak pengembang masih berakhir dengan UI test rapuh bahkan tanpa menggunakan perekam layar hanya karena tes mereka menunjukkan atribut yang sama.

Semua tes dalam artikel ini ditulis terhadap situs web Mvc Music Store. Situs web seperti ini memiliki beberapa masalah yang membuat pengujian UI agak sulit sehingga saya porting kode dan memperbaiki masalah. Anda dapat menemukan kode aktual yang saya tulis terhadap tes-tes ini di repo GitHub untuk artikel ini di sini

Jadi seperti apa tes rapuh itu? Itu terlihat seperti ini:

Anda dapat menemukan kelas BrittleTest di sini.

Host adalah kelas statis, dengan properti statis tunggal: Instance, yang ketika instantiasi menjalankan IIS Express di situs web yang sedang diuji dan mengikat Firefox WebDriver ke instance browser. Ketika tes selesai, kemudian menutup browser dan IIS Express secara otomatis.

Tes ini menjalankan peramban web, membuka laman beranda situs web Toko Musik Mvc, mendaftarkan pengguna baru, meramban album, menambahkannya ke keranjang, dan memeriksa.

Orang mungkin berpendapat tes ini terlalu banyak dan itu sebabnya rapuh; tetapi ukuran tes ini bukan alasan rapuh - tetapi bagaimana ini ditulis yang membuatnya menjadi mimpi buruk untuk dipertahankan.

Ada berbagai aliran pemikiran tentang pengujian UI dan seberapa banyak masing-masing tes harus mencakup. Beberapa percaya tes ini melakukan terlalu banyak dan beberapa berpikir tes harus mencakup skenario nyata, ujung ke ujung, dan menganggap ini tes yang sempurna (selain perawatan).

Jadi apa yang salah dengan tes ini?

  • Ini adalah kode prosedural. Salah satu masalah utama dari gaya pengkodean ini adalah keterbacaan, atau ketiadaannya. Jika Anda ingin mengubah tes, atau jika tes gagal karena salah satu halaman yang terlibat telah berubah, Anda akan kesulitan menentukan apa yang harus diubah dan menarik garis di antara bagian fungsionalitas; karena itu semua tumpukan kode di mana kita mendapatkan 'driver' untuk menemukan elemen pada halaman dan melakukan sesuatu dengannya. Tidak ada modularitas.
  • Tes yang satu ini dengan sendirinya mungkin tidak memiliki banyak duplikasi tetapi beberapa tes lagi seperti ini dan Anda akan memiliki banyak pemilih dan logika yang digandakan untuk berinteraksi dengan halaman web dari tes yang berbeda. Misalnya pemilihan By.Id("UserName") akan digandakan dalam semua tes yang memerlukan registrasi, dan driver.FindElement(By.Id("UserName")).Clear() dan driver.FindElement(By.Id("UserName ")).SendKeys ("") digandakan di mana saja Anda ingin berinteraksi dengan kotak teks UserName. Lalu ada seluruh formulir pendaftaran, dan formulir checkout dll. Yang akan diulang dalam semua tes yang perlu berinteraksi dengan mereka! Kode duplikat mengarah ke mimpi buruk perawatan.
  • Ada banyak string magic di mana-mana, yang lagi-lagi masalah pemeliharaan.

Kode Tes Adalah Kode!

Ada juga pola yang memungkinkan Anda untuk menulis tes UI yang lebih mudah dikelola.

Sama seperti kode Anda yang sebenarnya, Anda harus memelihara tes Anda. Jadi beri mereka perlakuan yang sama.

Ada apa dengan tes yang membuat kita berpikir kita bisa melepaskan kualitas di dalamnya? Jika ada, test suite yang buruk menurut saya jauh lebih sulit untuk dipelihara daripada kode yang buruk. Saya memiliki potongan kode kerja yang buruk dalam produksi selama bertahun-tahun yang tidak pernah rusak dan saya tidak pernah menyentuhnya. Tentu itu jelek dan sulit untuk dibaca dan dipelihara tetapi itu berhasil dan tidak perlu diubah sehingga biaya perawatan yang sebenarnya adalah nol. Namun situasinya tidak sama untuk tes yang buruk: karena tes yang buruk akan rusak dan memperbaikinya akan sulit. Saya tidak dapat menghitung berapa kali saya melihat pengembang menghindari pengujian karena mereka menganggap menulis tes adalah pemborosan waktu karena butuh terlalu banyak waktu untuk memeliharanya.

Kode tes adalah kode: Apakah Anda menerapkan SRP pada kode Anda? Maka Anda harus menerapkannya pada tes Anda juga. Apakah kode Anda DRY? Lalu DRY tes Anda juga. Jika Anda tidak menulis tes yang baik (UI atau lainnya), Anda akan membuang banyak waktu untuk memeliharanya.

Ada juga pola yang memungkinkan Anda untuk menulis tes UI yang lebih mudah dikelola. Pola-pola ini adalah platform agnostik: Saya telah menggunakan ide dan pola yang sama untuk menulis tes UI untuk aplikasi WPF dan aplikasi web yang ditulis dalam ASP.Net dan Ruby on Rails. Jadi, terlepas dari tumpukan teknologi Anda, Anda harus dapat membuat tes UI Anda lebih mudah dikelola dengan mengikuti beberapa langkah sederhana.

Memperkenalkan Pola Page Object

Banyak masalah yang disebutkan di atas berakar pada sifat prosedural dari skrip uji dan solusinya mudah: Orientasi Objek.

Halaman Obyek adalah pola yang digunakan untuk menerapkan orientasi objek ke tes UI. Dari Selenium wiki:

Dalam UI aplikasi web Anda, ada area yang berinteraksi dengan pengujian Anda. Page Object hanya memodelkan ini sebagai objek dalam kode tes. Ini mengurangi jumlah kode duplikat dan berarti bahwa jika perubahan UI, perbaikan hanya perlu diterapkan di satu tempat.

Idenya adalah bahwa untuk setiap halaman di aplikasi/situs web Anda, Anda ingin membuat satu Page Object. Page Object pada dasarnya setara dengan otomatisasi UI untuk halaman web Anda.

Saya telah maju dan me-refactor logika dan interaksi dari BrittleTest menjadi beberapa Page Object dan membuat tes baru yang menggunakannya daripada mengenai driver web secara langsung. Anda dapat menemukan tes baru di sini. Kode ini disalin di sini untuk referensi Anda:

Memang, ukuran body tes tidak berkurang banyak dan pada kenyataannya saya harus membuat tujuh kelas baru untuk mendukung tes ini. Meskipun diperlukan lebih banyak baris kode, kami hanya memperbaiki banyak masalah yang dimiliki oleh pengujian rapuh asli (lebih lanjut tentang ini lebih jauh ke bawah). Untuk sekarang, mari selami sedikit lebih dalam pola Page Object dan apa yang kami lakukan di sini.

Dengan pola Objek Halaman Anda biasanya membuat kelas objek halaman per halaman web yang sedang diuji di mana kelas memodelkan dan merangkum interaksi dengan halaman. Jadi kotak teks di halaman web Anda menjadi properti string pada Page Object dan untuk mengisi kotak teks itu, Anda cukup mengatur properti teks itu ke nilai yang diinginkan, daripada:

kita dapat menulis:

di mana registerPage adalah turunan dari kelas RegisterPage. Kotak centang pada halaman menjadi properti bool pada Page Object dan mencentang dan menghapus centang pada kotak centang hanyalah masalah mengatur bahwa properti boolean menjadi true atau false. Demikian juga, tautan pada halaman web menjadi metode pada Page Object dan mengklik tautan tersebut menjadi memanggil metode pada Page Object. Jadi daripada:

kita dapat menulis:

Bahkan, setiap tindakan pada halaman web kami menjadi metode dalam page object kami dan sebagai respons untuk mengambil tindakan itu (yaitu memanggil metode pada page object) Anda mendapatkan instance dari page object lain kembali yang menunjuk pada halaman web yang baru saja Anda buat. dinavigasi dengan mengambil tindakan (mis. mengirimkan formulir atau mengklik tautan). Dengan cara ini Anda dapat dengan mudah mengaitkan interaksi tampilan dalam skrip pengujian:

Di sini, setelah mendaftarkan pengguna saya akan dibawa ke halaman rumah (sebuah instance dari page object dikembalikan dengan metode SubmitRegistration). Jadi pada instance HomePage saya memanggil SelectGenreByName yang mengklik tautan 'Disco' pada halaman yang mengembalikan instance AlbumBrowsePage dan kemudian pada halaman itu saya memanggil SelectAlbumByName yang mengklik album 'Le Freak' dan mengembalikan instance dari AlbumDetailsPage dan sebagainya dan sebagainya.

Saya akui: banyak kelas untuk apa yang sebelumnya tidak ada kelas sama sekali; tapi kami mendapat banyak manfaat dari latihan ini. Pertama kode tidak lagi prosedural. Kami memiliki model pengujian yang lengkap di mana setiap objek menyediakan enkapsulasi interaksi yang bagus dengan sebuah halaman. Jadi misalnya jika sesuatu berubah dalam logika registrasi Anda, satu-satunya tempat yang harus Anda ubah adalah kelas RegisterPage Anda alih-alih harus melalui seluruh rangkaian tes dan mengubah setiap interaksi tunggal dengan tampilan registrasi. Modularitas ini juga memberikan kemudahan penggunaan kembali: Anda dapat menggunakan kembali ShoppingCartPage di mana pun Anda perlu berinteraksi dengan keranjang belanja. Jadi, dalam praktik sederhana perpindahan dari kode uji berorientasi prosedural ke objek, kami hampir menghilangkan tiga dari empat masalah dengan kode tes yang rapush dari awal yang merupakan kode prosedural, dan duplikasi logika dan selector. Kami masih memiliki sedikit duplikasi yang akan segera kami perbaiki.

Bagaimana kami benar-benar mengimplementasikan page object tersebut? page object di akarnya tidak lain adalah pembungkus interaksi yang Anda miliki dengan halaman. Di sini saya baru saja mengekstrak interaksi UI kami dari tes rapuh dan menempatkan mereka ke dalam page object mereka sendiri. Sebagai contoh, logika registrasi diekstraksi ke dalam kelasnya sendiri yang disebut RegisterPage yang terlihat seperti ini:

Saya telah membuat superclass Page yang menangani beberapa hal, seperti NavigateTo yang membantu menavigasi ke halaman baru dengan mengambil tindakan dan Execute yang menjalankan beberapa tindakan pada suatu elemen. Kelas Page tampak seperti:

Di BrittleTest, untuk berinteraksi dengan elemen, kami melakukan FindElement sekali per tindakan. Metode Execute, selain mengabstraksi interaksi driver web, memiliki manfaat tambahan yang memungkinkan memilih elemen, yang bisa menjadi tindakan mahal, sekali dan mengambil beberapa tindakan di atasnya:

digantikan dengan:

Melihat kedua objek halaman RegisterPage di atas kami masih memiliki sedikit duplikasi di sana. Kode uji adalah kode dan kami tidak ingin duplikasi dalam kode kami; jadi mari kita refactor itu. Kita dapat mengekstrak kode yang diperlukan untuk mengisi kotak teks ke metode pada kelas Page dan cukup memanggilnya dari page object. Metode ini dapat diimplementasikan sebagai:

Dan sekarang properti di RegisterPage dapat mengecil ke:

Anda juga dapat membuat API yang lancar agar setter terbaca lebih baik (mis. Fill("UserName").With(value)) tetapi saya akan menyerahkannya kepada Anda.

Kami tidak melakukan sesuatu yang luar biasa di sini. Hanya refactoring sederhana pada kode uji kami seperti yang selalu kami lakukan untuk kode kami, errrr, "lain" !!

Anda dapat melihat kode lengkap untuk kelas Page dan RegisterPage di sini dan di sini.

Page Object yang Strongly Typed

Kami menyelesaikan masalah prosedural dengan brittle test yang membuat tes lebih mudah dibaca, modular, DRY dan dapat dikelola secara efektif. Ada satu masalah terakhir yang tidak kami perbaiki: masih ada banyak magic string di mana-mana. Bukan mimpi buruk tapi masih masalah yang bisa kami perbaiki. Masukkan Page Object yang strongly typed!

Pendekatan ini praktis jika Anda menggunakan kerangka kerja MV * untuk UI Anda. Dalam kasus kami, kami menggunakan ASP.Net MVC.

Mari kita lihat lagi pada RegisterPage:

Halaman ini memodelkan tampilan Register di aplikasi web kami (hanya menyalin sedikit diatas di sini untuk kenyamanan Anda):

Hmmm, apa itu RegisterModel di sana? Ini adalah View Model  untuk halaman: M dalam MVC. Ini kodenya (saya menghapus atribut untuk mengurangi kegaduhan):

Itu terlihat sangat akrab, bukan? Ini memiliki properti yang sama dengan kelas RegisterPage yang tidak mengejutkan mengingat RegisterPage dibuat berdasarkan view dan view model Mari kita lihat apakah kita dapat memanfaatkan view model untuk menyederhanakan page object kita

Saya telah membuat superclass Page baru; tapi yang generik. Anda dapat melihat kode di sini:

Kelas Page<TViewModel> mensubclass kelas Page lama dan menyediakan semua fungsinya; tetapi juga memiliki satu metode tambahan yang disebut FillWith yang mengisi halaman dengan instance view model yang disediakan! Jadi sekarang kelas RegisterPage saya terlihat seperti:

Saya menduplikasi semua page object untuk menampilkan kedua variasi dan juga untuk membuat basis kode lebih mudah diikuti untuk Anda; tetapi pada kenyataannya Anda akan membutuhkan satu kelas untuk setiap page object.

Setelah mengonversi page oject saya menjadi objek generik sekarang tesnya terlihat seperti:

Itu saja - seluruh tes! Jauh lebih mudah dibaca, DRY, dan bisa dipelihara, bukan?

Kelas ObjectMother yang saya gunakan dalam tes adalah Object Mother yang menyediakan data uji (kode dapat ditemukan di sini), tidak ada yang mewah:

Jangan Berhenti di Page Object

Beberapa halaman web sangat besar dan kompleks. Sebelumnya saya mengatakan kode tes adalah kode dan kita harus memperlakukannya seperti itu. Kami biasanya memecah halaman web yang besar dan kompleks menjadi komponen yang lebih kecil dan, dalam beberapa kasus, dapat digunakan kembali (sebagian). Ini memungkinkan kami membuat halaman web dari komponen yang lebih kecil dan lebih mudah dikelola. Kita harus melakukan hal yang sama untuk pengujian kita. Untuk melakukan ini kita dapat menggunakan Page Component.

Page Component cukup mirip dengan Page Object: Ini adalah kelas yang merangkum interaksi dengan beberapa elemen pada halaman. Perbedaannya adalah bahwa ia berinteraksi dengan sebagian kecil halaman web: itu memodelkan kontrol pengguna atau tampilan sebagian, jika Anda mau. Contoh yang baik untuk komponen halaman adalah bilah menu. Bilah menu biasanya muncul di semua halaman aplikasi web. Anda tidak benar-benar ingin terus mengulang kode yang diperlukan untuk berinteraksi dengan menu di setiap page object. Sebagai gantinya Anda dapat membuat page component menu dan menggunakannya dari page object Anda. Anda juga bisa menggunakan page component untuk menangani data grid pada halaman Anda, dan untuk mengambil langkah lebih jauh page component grid itu sendiri dapat terdiri dari page component baris grid. Dalam hal Mvc Music Store kita bisa memiliki TopMenuComponent dan SideMenuComponent dan menggunakannya dari HomePage kita.

Seperti di aplikasi web Anda, Anda juga bisa membuat, misalnya, objek halaman LayoutPage yang memodelkan tata letak/halaman master Anda dan menggunakannya sebagai superclass untuk semua page object lainnya. Halaman tata letak kemudian akan terdiri dari page component menu sehingga semua halaman dapat menekan menu. Saya kira aturan praktis yang baik adalah memiliki komponen halaman per tampilan parsial, page object tata letak per tata letak dan page object per halaman web. Dengan begitu Anda tahu kode pengujian sama granualar dan tersusun dengan baik sebagai kode Anda.

Beberapa Kerangka untuk Pengujian UI

Apa yang saya perlihatkan di atas adalah sampel yang sangat sederhana dan dibuat-buat dengan beberapa kelas pendukung sebagai infrastruktur untuk pengujian. Pada kenyataannya persyaratan untuk pengujian UI jauh lebih kompleks dari itu: ada kontrol dan interaksi yang kompleks, Anda harus menulis dan membaca dari halaman Anda, Anda harus berurusan dengan latensi jaringan dan memiliki kontrol atas AJAX dan interaksi Javascript lainnya, perlu memadamkan browser yang berbeda dan yang saya tidak jelaskan di artikel ini. Meskipun memungkinkan untuk mengode semua ini, menggunakan beberapa kerangka kerja dapat menghemat banyak waktu. Berikut adalah kerangka kerja yang sangat saya rekomendasikan:

Kerangka kerja untuk .Net:

  • Seleno adalah proyek sumber terbuka dari TestStack yang membantu Anda menulis tes UI otomatis dengan Selenium. Ini berfokus pada penggunaan Page Object dan Page Component dan dengan membaca dari dan menulis ke halaman web menggunakan view model yang strong typed. Jika Anda menyukai apa yang saya lakukan dalam artikel ini, maka Anda juga akan menyukai Seleno karena sebagian besar kode yang ditampilkan di sini dipinjam dari basis kode Seleno.
  • White adalah kerangka kerja open source dari TestStack untuk mengotomatisasi aplikasi klien kaya berdasarkan platform Win32, WinForms, WPF, Silverlight dan SWT (Java).

Pengungkapan: Saya adalah salah satu pendiri dan anggota tim pengembangan di organisasi TestStack.

Kerangka kerja untuk Ruby:

  • Capybara adalah kerangka kerja acceptance test aplikasi web yang membantu Anda menguji aplikasi web dengan mensimulasikan bagaimana pengguna nyata akan berinteraksi dengan aplikasi Anda.
  • Poltergeist adalah driver untuk Capybara. Hal ini memungkinkan Anda untuk menjalankan tes Capybara Anda pada browser WebKit headless, yang disediakan oleh PhantomJS.
  • page-object (saya belum menggunakan gem ini secara pribadi) adalah gem sederhana yang membantu menciptakan page object yang fleksibel untuk menguji aplikasi berbasis browser. Tujuannya adalah untuk memfasilitasi membuat lapisan abstraksi dalam tes Anda untuk memisahkan tes dari item yang mereka uji dan untuk menyediakan antarmuka sederhana ke elemen-elemen pada halaman. Ia bekerja dengan watir-webdriver dan selenium-webdriver.

Kesimpulan

Kami mulai dengan pengalaman otomatisasi UI yang khas, menjelaskan mengapa pengujian UI gagal, memberikan contoh uji yang rapuh dan membahas masalah-masalahnya dan menyelesaikannya menggunakan beberapa ide dan pola.

Jika Anda ingin mengambil satu poin dari artikel ini, seharusnya: Kode tes adalah Kode. Jika Anda memikirkannya, semua yang saya lakukan dalam artikel ini adalah menerapkan pengkodean yang baik dan praktik berorientasi objek yang sudah Anda ketahui untuk tes UI.

Masih banyak yang harus dipelajari tentang pengujian UI dan saya akan mencoba untuk membahas beberapa tips lebih lanjut di artikel mendatang.

Happy Testing!

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.