Di bagian
pertama artikel, kami menulis server web kecil, yang merupakan backend untuk sistem informasi kami. Bagian itu tidak terlalu menarik, meskipun itu menunjukkan penggunaan antarmuka dan salah satu metode untuk bekerja dengan goroutine. Baik itu dan yang lain bisa menarik bagi pengembang pemula.
Bagian kedua jauh lebih menarik dan berguna, karena di dalamnya kita akan menulis unit test baik untuk server itu sendiri maupun untuk paket perpustakaan yang mengimplementasikan data warehouse. Mari kita mulai.
gambar dari siniJadi, izinkan saya mengingatkan Anda bahwa aplikasi kami terdiri dari modul yang dapat dieksekusi (server web, API), modul penyimpanan (struktur data entitas, antarmuka kontrak untuk penyedia penyimpanan) dan modul penyedia penyimpanan (dalam contoh kami, hanya ada satu modul yang menjalankan antarmuka penyimpanan data dalam memori).
Kami akan menguji modul yang dapat dieksekusi dan implementasi penyimpanan. Modul kontrak tidak mengandung kode yang dapat diuji. Hanya ada deklarasi tipe.
Untuk pengujian, kami hanya akan menggunakan kemampuan pustaka standar - paket pengujian dan httptest. Menurut saya, mereka cukup, meskipun ada banyak kerangka kerja pengujian yang berbeda. Lihat mereka, mungkin Anda akan menyukainya. Dari sudut pandang saya, program on Go tidak benar-benar membutuhkan kerangka kerja (dari berbagai jenis) yang ada saat ini. Ini bukan Javascript untuk Anda, yang akan dibahas di bagian ketiga artikel.
Pertama, beberapa kata tentang metodologi pengujian yang saya gunakan untuk program Go.
Pertama , saya harus mengatakan bahwa saya sangat suka Go hanya karena tidak mendorong programmer ke beberapa kerangka kerja yang kaku. Meskipun beberapa pengembang, dalam keadilan, suka mengarahkan diri mereka ke dalam kerangka kerja yang dibawa dari PL sebelumnya. Katakan, Rob Pike yang sama, mengatakan bahwa dia tidak melihat masalah dalam menyalin kode, jika itu lebih mudah. Copy-paste seperti itu bahkan ada di perpustakaan standar. Alih-alih mengimpor paket, salah satu penulis bahasa hanya menyalin teks dari satu fungsi (verifikasi Unicode). Dalam pengujian ini, paket Unicode diimpor, jadi semuanya OK.
Ngomong-ngomong, dalam pengertian ini (dalam arti fleksibilitas bahasa), teknik yang menarik dapat digunakan saat menulis tes. Intinya adalah ini: kita tahu bahwa kontrak antarmuka di Go dijalankan secara implisit. Artinya, kita dapat mendeklarasikan tipe, menulis metode untuk itu, dan menjalankan semacam kontrak. Mungkin bahkan tanpa menyadarinya. Ini dikenal dan dipahami. Namun, ini juga bekerja berlawanan arah. Jika pembuat beberapa modul tidak menulis antarmuka yang akan membantu kami membuat rintisan untuk menguji paket kami, maka kami dapat mendeklarasikan antarmuka dalam pengujian kami, yang akan dieksekusi dalam paket pihak ketiga. Gagasan yang bermanfaat, meskipun itu tidak berguna dalam aplikasi pelatihan kami.
Kedua , beberapa kata tentang waktu penulisan tes. Seperti semua orang tahu, ada pendapat berbeda tentang kapan harus menulis tes unit. Gagasan utamanya adalah sebagai berikut:
- Kami menulis tes sebelum menulis kode (TDD). Dengan demikian, kami lebih memahami tugas dan menetapkan kriteria kualitas.
- Kami menulis tes saat menulis kode, atau bahkan beberapa saat kemudian (kami akan mempertimbangkan pembuatan prototipe tambahan ini).
- Kami akan menulis tes beberapa saat kemudian, jika ada waktu. Dan ini bukan lelucon. Terkadang kondisinya sedemikian rupa sehingga secara fisik tidak ada waktu.
Saya tidak berpikir bahwa ada satu-satunya pendapat yang benar tentang hal ini. Saya akan membagikan milik saya dan meminta pembaca untuk berkomentar di komentar. Pendapat saya adalah ini:
- Mengembangkan paket berdiri bebas di TDD, ini benar-benar menyederhanakan masalah, terutama ketika memulai aplikasi untuk verifikasi adalah proses yang intensif sumber daya. Sebagai contoh, saya baru-baru ini mengembangkan sistem pemantauan kendaraan GPS / GLONASS. Paket driver untuk protokol hanya dapat dikembangkan melalui tes, karena meluncurkan dan memeriksa aplikasi secara manual membutuhkan menunggu data dari pelacak, yang sangat merepotkan. Untuk tes, saya mengambil sampel paket data, merekamnya dalam tes tabel, dan tidak memulai server sampai driver siap.
- Jika struktur kode tidak jelas, maka pertama-tama saya mencoba membuat prototipe yang berfungsi minimal. Lalu saya menulis tes, atau bahkan pertama memoles kode sedikit dan kemudian hanya tes.
- Untuk modul yang dapat dieksekusi, saya pertama kali menulis prototipe. Tes nanti. Saya sama sekali tidak menguji kode yang dapat dieksekusi yang jelas (Anda dapat mengetik peluncuran server http dari utama ke fungsi terpisah dan menyebutnya dalam pengujian, tetapi mengapa menguji perpustakaan standar?)
Berdasarkan hal ini, dalam aplikasi pelatihan kami, penyedia penyimpanan RAM ditulis melalui tes. Server yang dapat dieksekusi dibuat melalui prototipe.
Mari kita mulai dengan tes untuk mengimplementasikan repositori.
Dalam repositori, kami memiliki metode pabrik New (), yang mengembalikan pointer ke turunan dari tipe penyimpanan. Ada juga metode untuk mendapatkan penawaran Efek (), menambahkan kertas ke daftar Tambah (), dan menginisialisasi penyimpanan dengan data dari server Mosbirzh InitData ().
Menguji konstruktor (istilah OOP digunakan secara bebas, informal. Sepenuhnya sesuai dengan posisi OOP in Go).
Dalam tes ini, tanpa kebutuhan khusus, satu-satunya cara di Go ditunjukkan untuk memeriksa jenis variabel adalah refleksi (reflect.TypeOf (memoryStorage)). Penggunaan modul ini secara berlebihan tidak disarankan. Tantangannya berat, dan sama sekali tidak sepadan. Di sisi lain, apa lagi yang harus diperiksa dalam tes ini selain tidak adanya kesalahan?
Selanjutnya, kami menguji penerimaan tanda kutip dan penambahan kertas. Tes-tes ini sebagian saling menduplikasi, tetapi ini tidak penting (dalam tes untuk menambah kertas, metode untuk mendapatkan penawaran untuk verifikasi disebut). Secara umum, saya terkadang menulis satu tes untuk semua operasi CRUD untuk entitas tertentu. Yaitu, dalam pengujian saya membuat entitas, membacanya, mengubahnya, membacanya lagi, menghapusnya, membacanya lagi. Tidak terlalu elegan, tetapi kekurangan yang jelas tidak terlihat.
Tes kutipan.
Semuanya cukup jelas di sini.
Sekarang coba untuk menambahkan kertas. Dalam tes ini, untuk tujuan pendidikan (tanpa kebutuhan nyata), kami akan menggunakan teknik pengujian tabel yang sangat nyaman. Esensinya adalah sebagai berikut: kami membuat larik struktur yang tidak disebutkan namanya, yang masing-masing berisi data input untuk pengujian dan hasil yang diharapkan. Dalam kasus kami, kami mengirimkan sekuritas untuk ditambahkan, hasilnya adalah jumlah sekuritas di brankas (panjang array). Selanjutnya, kami melakukan tes untuk setiap elemen array struktur (memanggil metode pengujian dengan data input elemen) dan membandingkan hasilnya dengan bidang hasil elemen saat ini. Ternyata sesuatu seperti ini.
Nah, tes untuk fungsi inisialisasi data.
Sebagai hasil dari eksekusi tes yang sukses, kami mendapatkan:
17.595 cakupan: 86.0% pernyataan.Anda dapat mengatakan bahwa akan lebih baik jika perpustakaan terpisah mendapatkan cakupan 100%, tetapi secara khusus di sini jalur eksekusi yang gagal (kesalahan dalam fungsi) tidak mungkin sama sekali, karena fitur implementasi - semuanya ada dalam memori, kami tidak terhubung di mana pun, kami tidak bergantung pada apa pun. Secara formal ada penanganan kesalahan, karena kontrak antarmuka menyebabkan kesalahan dikembalikan dan linter membutuhkannya.
Mari kita beralih ke menguji paket yang dapat dieksekusi - server web. Harus dikatakan bahwa karena server web adalah konstruksi super-standar dalam program Go, paket βnet / http / httptestβ secara khusus dikembangkan untuk menguji penangan permintaan http. Ini memungkinkan Anda untuk mensimulasikan server web, menjalankan penangan permintaan dan merekam respons server web dalam struktur khusus. Kami akan menggunakannya, sangat sederhana, pasti Anda akan menyukainya.
Pada saat yang sama, ada pendapat (dan bukan hanya pendapat saya) bahwa tes semacam itu mungkin tidak terlalu relevan dengan sistem kerja nyata. Anda dapat, pada prinsipnya, memulai server nyata dan memanggil penangan koneksi nyata dalam tes.
Benar, ada pendapat lain (dan juga bukan hanya milikku) bahwa mengisolasi logika bisnis dari sistem untuk memanipulasi data nyata itu bagus.
Dalam pengertian ini, kita dapat mengatakan bahwa kita sedang menulis tes unit, bukan tes integrasi yang melibatkan paket dan layanan lain. Meskipun di sini saya juga berpendapat bahwa fleksibilitas Go tertentu memungkinkan Anda untuk tidak fokus pada persyaratan dan menulis tes yang paling cocok untuk tugas Anda. Biarkan saya memberi Anda sebuah contoh: untuk pengujian penangan permintaan API, saya membuat salinan database yang disederhanakan pada server nyata di jaringan, diinisialisasi dengan set data kecil dan menjalankan tes pada data nyata. Tetapi pendekatan ini sangat situasional.
Kembali ke pengujian server web kami. Untuk menulis tes yang tidak tergantung pada penyimpanan aktual, kita perlu mengembangkan penyimpanan rintisan. Ini tidak sulit sama sekali, karena kami bekerja dengan repositori melalui antarmuka (lihat bagian pertama). Yang perlu kita lakukan adalah mendeklarasikan beberapa tipe data kita sendiri dan mengimplementasikan metode kontrak antarmuka penyimpanan untuknya, bahkan dengan data kosong. Sesuatu seperti ini:
Sekarang kita dapat menginisialisasi penyimpanan kita dengan sebuah rintisan. Bagaimana cara melakukannya? Untuk tujuan menginisialisasi lingkungan pengujian di Go dari beberapa versi yang tidak terlalu kuno, fungsi ditambahkan:
func TestMain(m *testing.M)
Fungsi ini memungkinkan Anda untuk menginisialisasi dan menjalankan semua tes. Itu terlihat seperti ini:
Sekarang kita dapat menulis tes untuk penangan permintaan API. Kami memiliki dua titik akhir API, dua penangan, dan karenanya dua tes. Mereka sangat mirip, jadi ini yang pertama.
Inti dari tes ini adalah: membuat permintaan http, menetapkan struktur untuk merekam respons server, memulai penangan permintaan, mendekode badan respons (json ke dalam struktur). Nah, untuk kejelasan, kami mencetak jawabannya.
Ternyata sesuatu seperti:
=== Jalankan TestSecurityHandler
0xc00005e3e0
- LULUS: TestSecurityHandler (0,00)
c: \ Users \ dtsp \ YandexDisk \ go \ src \ moex_etf \ server \ server_test.go: 96:
[{ID: Nama MSFT: Microsoft IssueDate: 1514764800 Kutipan: [{SecurityID: MSFT Jumlah: 0 TimeStamp: 1514764800 Harga: 100}]}]
Lulus
ok moex_etf / server 0.307s
Sukses: Tes lulus.
Kode
github .
Pada bagian akhir artikel berikutnya, kami akan mengembangkan aplikasi web untuk menampilkan grafik pengembalian saham riil pada ETF di Moscow Exchange.