Salut untuk semua orang! Kurang dari satu minggu tersisa sebelum dimulainya kursus
"Pengembang Golang" dan kami terus membagikan materi yang bermanfaat tentang topik tersebut. Ayo pergi!

Go memiliki perpustakaan bawaan yang baik dan dapat diandalkan untuk pengujian. Jika Anda menulis di Go, maka Anda sudah tahu itu. Pada artikel ini, kami akan berbicara tentang beberapa strategi yang dapat meningkatkan keterampilan pengujian Anda dengan Go. Dari pengalaman menulis basis kode kami yang mengesankan di Go, kami belajar bahwa strategi ini benar-benar bekerja dan dengan demikian membantu menghemat waktu dan upaya dalam bekerja dengan kode.
Gunakan suite tesJika Anda belajar untuk diri sendiri hanya satu hal yang bermanfaat dari artikel ini, maka itu harus menggunakan test suites. Bagi mereka yang tidak terbiasa dengan konsep ini, pengujian oleh kit adalah proses mengembangkan tes untuk menguji antarmuka umum yang dapat digunakan pada banyak implementasi dari antarmuka ini. Di bawah ini Anda dapat melihat bagaimana kami melewati beberapa implementasi
Thinger
berbeda dan menjalankannya dengan tes yang sama.
type Thinger interface { DoThing(input string) (Result, error) }
Pembaca yang beruntung telah bekerja dengan basis kode yang menggunakan metode ini. Sering digunakan dalam pengujian sistem berbasis plugin yang ditulis untuk menguji antarmuka dapat digunakan oleh semua implementasi antarmuka ini untuk memahami bagaimana mereka memenuhi persyaratan perilaku.
Menggunakan pendekatan ini berpotensi membantu menghemat jam, hari, dan bahkan cukup waktu untuk menyelesaikan masalah kesetaraan
kelas P dan NP . Juga, ketika mengganti satu sistem basis dengan yang lain, kebutuhan untuk menulis (sejumlah besar) tes tambahan menghilang, dan ada juga kepercayaan bahwa pendekatan ini tidak akan mengganggu operasi aplikasi Anda. Secara implisit, Anda perlu membuat antarmuka yang mendefinisikan area area yang diuji. Menggunakan injeksi ketergantungan, Anda dapat menyesuaikan satu set dari paket yang diteruskan ke dalam implementasi seluruh paket.
Anda dapat menemukan contoh lengkap di
sini . Terlepas dari kenyataan bahwa contoh ini tidak masuk akal, orang dapat membayangkan bahwa satu database jauh dan yang lainnya ada dalam memori.
Contoh keren lain dari teknik ini terletak di perpustakaan standar dalam paket
golang.org/x/net/nettest
. Ini menyediakan sarana untuk memverifikasi bahwa net.Conn memuaskan antarmuka.
Hindari kontaminasi antarmukaAnda tidak dapat berbicara tentang pengujian di Go, tetapi jangan berbicara tentang antarmuka.
Antarmuka penting dalam konteks pengujian, karena mereka adalah alat yang paling kuat dalam gudang pengujian kami, jadi Anda harus menggunakannya dengan benar.
Paket sering mengekspor antarmuka ke pengembang, dan ini mengarah pada fakta bahwa:
A) Pengembang membuat tiruan mereka sendiri untuk mengimplementasikan paket;
B) Paket mengekspor tiruannya sendiri.
“Semakin besar antarmuka, semakin lemah abstraksi”
- Rob Pike, Sayings of Go
Antarmuka harus diperiksa dengan cermat sebelum ekspor. Sering tergoda untuk mengekspor antarmuka untuk memberikan pengguna kemampuan untuk mensimulasikan perilaku yang mereka butuhkan. Alih-alih, dokumentasikan antarmuka mana yang sesuai dengan struktur Anda agar tidak menciptakan hubungan yang erat antara paket konsumen dan milik Anda. Contoh yang bagus dari ini adalah paket
kesalahan .
Saat kami memiliki antarmuka yang tidak ingin kami ekspor, kami dapat menggunakan
subtree internal / paket untuk menyimpannya di dalam paket. Dengan demikian, kita tidak dapat takut bahwa pengguna akhir dapat bergantung padanya, dan, oleh karena itu, mungkin fleksibel dalam mengubah antarmuka sesuai dengan persyaratan baru. Biasanya kami membuat antarmuka dengan dependensi eksternal agar dapat menjalankan tes secara lokal.
Pendekatan ini memungkinkan pengguna untuk mengimplementasikan antarmuka kecil mereka sendiri dengan hanya membungkus beberapa bagian perpustakaan untuk pengujian. Untuk informasi lebih lanjut tentang konsep ini, baca
artikel rakyl tentang polusi antarmuka .
Jangan mengekspor primitif konkurensiGo menawarkan primitif konkurensi yang mudah digunakan yang kadang-kadang juga dapat menyebabkan penggunaan berlebihan karena kesederhanaan yang sama. Pertama-tama, kami memperhatikan saluran dan paket sinkronisasi. Terkadang tergoda untuk mengekspor saluran dari paket Anda sehingga orang lain dapat menggunakannya. Selain itu, kesalahan umum adalah menyematkan
sync.Mutex
tanpa mengaturnya ke pribadi. Ini, seperti biasa, tidak selalu buruk, tetapi menciptakan masalah tertentu saat menguji program Anda.
Jika Anda mengekspor saluran, Anda juga mempersulit kehidupan pengguna paket, yang tidak layak dilakukan. Segera setelah saluran diekspor dari paket, Anda membuat kesulitan saat menguji orang yang menggunakan saluran ini. Agar pengujian berhasil, pengguna harus tahu:
- Ketika data akhirnya dikirim melalui saluran.
- Apakah ada kesalahan saat menerima data.
- Bagaimana paket menyiram saluran setelah selesai, jika menyiram sama sekali?
- Bagaimana cara membungkus API paket sehingga Anda tidak dapat meneleponnya langsung?
Lihatlah contoh bacaan antrian. Berikut ini adalah contoh perpustakaan yang membaca dari antrian dan menyediakan umpan kepada pengguna untuk dibaca.
type Reader struct {...} func (r *Reader) ReadChan() <-chan Msg {...}
Sekarang pengguna perpustakaan Anda ingin menerapkan tes untuk penggunanya:
func TestConsumer(t testing.T) { cons := &Consumer{ r: libqueue.NewReader(), } for msg := range cons.r.ReadChan() {
Pengguna kemudian dapat memutuskan bahwa injeksi ketergantungan adalah ide yang bagus dan menulis pesan mereka sendiri di saluran:
func TestConsumer(t testing.T, q queueIface) { cons := &Consumer{ r: q, } for msg := range cons.r.ReadChan() {
Tunggu, bagaimana dengan kesalahannya?
func TestConsumer(t testing.T, q queueIface) { cons := &Consumer{ r: q, } for { select { case msg := <-cons.r.ReadChan():
Sekarang kita perlu entah bagaimana menghasilkan peristiwa untuk benar-benar menulis ke tulisan rintisan ini, yang mereplikasi perilaku perpustakaan yang kita gunakan. Jika perpustakaan hanya menulis API sinkron, maka kita bisa menambahkan semua paralelisme ke kode klien, jadi pengujian menjadi lebih mudah.
func TestConsumer(t testing.T, q queueIface) { cons := &Consumer{ r: q, } msg, err := cons.r.ReadMsg()
Jika Anda ragu, ingatlah bahwa selalu mudah untuk menambahkan paralelisme ke paket konsumen (paket konsumsi), dan sulit atau tidak mungkin untuk menghapusnya setelah mengekspor dari perpustakaan. Dan yang paling penting, jangan lupa untuk menulis dalam dokumentasi paket apakah struktur / paket tersebut aman untuk akses simultan ke beberapa goroutine.
Terkadang masih diinginkan atau perlu untuk mengekspor saluran. Untuk mengurangi beberapa masalah yang disebutkan di atas, Anda dapat menyediakan saluran melalui accessor alih-alih akses langsung dan membiarkannya terbuka hanya untuk membaca (
←chan
) atau hanya untuk menulis (
chan←
) ketika mendeklarasikan.
Gunakan net/http/httptest
Httptest
memungkinkan
Httptest
untuk mengeksekusi kode
http.Handler
tanpa memulai server atau mengikat ke port. Ini mempercepat pengujian dan memungkinkan Anda untuk menjalankan tes secara paralel dengan biaya lebih rendah.
Berikut adalah contoh dari tes yang sama diimplementasikan dalam dua cara. Tidak ada yang muluk di sini, tetapi pendekatan ini mengurangi jumlah kode dan menghemat sumber daya.
func TestServe(t *testing.T) {
Mungkin fitur yang paling penting adalah dengan
httptest
Anda hanya dapat membagi tes menjadi fungsi yang ingin Anda uji. Tidak ada router, middleware, atau efek samping lain yang muncul ketika mengatur server, layanan, pabrik prosesor, pabrik prosesor, atau hal lain yang menurut Anda akan menjadi ide yang baik.
Untuk melihat prinsip ini dalam tindakan, lihat
artikel Marc Berger .
Gunakan paket terpisah _test
Sebagian besar pengujian dalam ekosistem dibuat dalam file
pkg_test.go
, tetapi masih tetap dalam paket yang sama:
package pkg
. Paket pengujian terpisah adalah paket yang Anda buat di file baru,
foo_test.go
, di direktori modul yang ingin Anda uji,
foo/
, dengan
package foo_test
deklarasi
package foo_test
. Dari sini Anda dapat mengimpor
github.com/example/foo
dan dependensi lainnya. Fitur ini memungkinkan Anda melakukan banyak hal. Ini adalah solusi yang direkomendasikan untuk dependensi siklik dalam pengujian, mencegah munculnya "tes rapuh" dan memungkinkan pengembang untuk merasakan seperti apa rasanya menggunakan paket Anda sendiri. Jika paket Anda sulit digunakan, maka pengujian dengan metode ini juga akan sulit.
Strategi ini mencegah uji rapuh dengan membatasi akses ke variabel pribadi. Secara khusus, jika tes Anda rusak dan Anda menggunakan paket tes terpisah, hampir dijamin bahwa klien yang menggunakan fungsi yang rusak dalam tes juga akan rusak ketika dipanggil.
Akhirnya, membantu menghindari siklus impor dalam pengujian. Sebagian besar paket lebih cenderung bergantung pada paket lain yang Anda tulis di samping paket pengujian, sehingga Anda akan berakhir dengan situasi di mana siklus impor terjadi secara alami. Paket eksternal terletak di atas kedua paket dalam hierarki paket. Ambil sebuah contoh dari The Go Programming Language (Bab 11 Bagian 2.4), di mana
net/url
mengimplementasikan parser URL yang diimpor
net/http
untuk digunakan. Namun,
net / url
perlu diuji dengan case use nyata dengan mengimpor
net / http
. Jadi
net/url_test
.
Sekarang, ketika Anda menggunakan paket pengujian terpisah, Anda mungkin perlu akses ke entitas yang tidak diekspor dalam paket di mana mereka sebelumnya tersedia. Beberapa pengembang dihadapkan dengan ini untuk pertama kalinya ketika menguji sesuatu berdasarkan waktu (misalnya, waktu. Sekarang menjadi sebuah rintisan menggunakan fungsi). Dalam hal ini, kami dapat menggunakan file tambahan untuk menyediakan entitas secara eksklusif selama pengujian, karena file
_test.go
dikecualikan dari build biasa.
Apa yang perlu Anda ingat?Penting untuk diingat bahwa tidak ada metode yang dijelaskan di atas adalah obat mujarab. Pendekatan terbaik dalam bisnis apa pun adalah dengan menganalisis situasi secara kritis dan secara mandiri memilih solusi terbaik untuk masalah tersebut.
Ingin mempelajari lebih lanjut tentang pengujian dengan Go?
Baca artikel ini:
Dave Cheney's Writing Table Driven Tests in GoBab Bahasa Pemrograman Go tentang Pengujian.Atau tonton video ini:
Pembicaraan Lanjutan Pengujian Hashimoto dengan Go dari Gophercon 2017Teknik Pengujian Andrew Gerrand berbicara mulai tahun 2014Kami berharap terjemahan ini bermanfaat bagi Anda. Kami menunggu komentar, dan semua orang yang ingin mempelajari lebih lanjut tentang kursus, kami mengundang Anda untuk
membuka hari , yang akan diadakan pada 23 Mei.