Apakah ini praktik yang baik untuk menjalankan tes unit di kait kontrol versi?

43

Dari sudut pandang teknis dimungkinkan untuk menambahkan beberapa kait push pra / pasca yang akan menjalankan tes unit sebelum memungkinkan beberapa komit tertentu untuk digabung ke cabang default jauh.

Pertanyaan saya adalah - apakah lebih baik untuk menjaga unit test dalam membangun pipa (dengan demikian, memperkenalkan komitmen rusak untuk repo) atau lebih baik tidak membiarkan komitmen "buruk" terjadi.

Saya sadar bahwa saya tidak terbatas dengan dua opsi ini. Misalnya, saya dapat mengizinkan semua komit untuk dicabang dan diuji sebelum mendorong komit gabungan untuk repo. Tetapi jika Anda harus memilih di antara dua solusi ini, yang mana yang akan Anda pilih dan untuk alasan apa?

shabunc
sumber

Jawaban:

35

Tidak, bukan karena dua alasan:

Kecepatan

Komitmen harus cepat. Komit yang membutuhkan 500 ms., Misalnya, terlalu lambat dan akan mendorong pengembang untuk melakukan lebih hemat. Mengingat bahwa pada proyek apa pun yang lebih besar dari Hello World, Anda akan memiliki lusinan atau ratusan pengujian, akan membutuhkan terlalu banyak waktu untuk menjalankannya selama pra-komit.

Tentu saja, keadaan menjadi lebih buruk untuk proyek yang lebih besar dengan ribuan tes yang berjalan selama beberapa menit pada arsitektur terdistribusi, atau berminggu-minggu atau berbulan-bulan pada satu mesin.

Bagian terburuknya adalah tidak banyak yang dapat Anda lakukan untuk membuatnya lebih cepat. Proyek-proyek Python kecil yang, katakanlah, ratusan unit test, membutuhkan setidaknya satu detik untuk berjalan di server rata-rata, tetapi seringkali jauh lebih lama. Untuk aplikasi C #, itu akan rata-rata empat-lima detik, karena waktu kompilasi.

Dari titik itu, Anda dapat membayar ekstra $ 10.000 untuk server yang lebih baik yang akan mengurangi waktu, tetapi tidak banyak, atau menjalankan tes pada beberapa server, yang hanya akan memperlambat segalanya.

Keduanya membayar dengan baik ketika Anda memiliki ribuan tes (serta tes fungsional, sistem dan integrasi), memungkinkan untuk menjalankannya dalam hitungan menit, bukan minggu, tetapi ini tidak akan membantu Anda untuk proyek skala kecil.

Yang dapat Anda lakukan, sebaliknya, adalah:

  • Dorong pengembang untuk menjalankan tes yang sangat terkait dengan kode yang mereka modifikasi secara lokal sebelum melakukan komit. Mereka mungkin tidak dapat menjalankan ribuan unit test, tetapi mereka dapat menjalankan lima-sepuluh dari mereka.

    Pastikan menemukan tes yang relevan dan menjalankannya sebenarnya mudah (dan cepat). Visual Studio, misalnya, mampu mendeteksi tes mana yang mungkin dipengaruhi oleh perubahan yang dilakukan sejak menjalankan terakhir. IDE / platform / bahasa / kerangka kerja lain mungkin memiliki fungsi yang serupa.

  • Pertahankan komit secepat mungkin. Menegakkan aturan gaya tidak apa-apa, karena seringkali, itu satu-satunya tempat untuk melakukannya, dan karena pemeriksaan seperti itu sering kali sangat cepat. Melakukan analisis statis adalah OK begitu tetap cepat, yang jarang terjadi. Tes unit yang berjalan tidak OK.

  • Jalankan tes unit pada server Integrasi Berkelanjutan Anda.

  • Pastikan pengembang mendapat informasi secara otomatis ketika mereka melanggar build (atau ketika unit test gagal, yang praktis adalah hal yang sama jika Anda menganggap kompiler sebagai alat yang memeriksa beberapa kesalahan yang mungkin Anda dapat masukkan ke dalam kode Anda).

    Misalnya, membuka halaman web untuk memeriksa build terakhir bukanlah solusi. Mereka harus diinformasikan secara otomatis . Menampilkan sembulan atau mengirim SMS adalah dua contoh bagaimana mereka dapat diinformasikan.

  • Pastikan pengembang memahami bahwa melanggar build (atau gagal tes regresi) tidak OK, dan segera setelah itu terjadi, prioritas utama mereka adalah untuk memperbaikinya. Tidak masalah apakah mereka mengerjakan fitur prioritas tinggi yang diminta bos mereka untuk dikirim besok: mereka gagal membangun, mereka harus memperbaikinya.

Keamanan

Server yang menampung repositori tidak boleh menjalankan kode khusus, seperti pengujian unit, terutama untuk alasan keamanan. Alasan-alasan itu sudah dijelaskan di CI runner di server yang sama dengan GitLab?

Jika, di sisi lain, ide Anda adalah meluncurkan proses pada server build dari pre-commit hook, maka itu akan memperlambat lebih banyak komit.

Arseni Mourzenko
sumber
4
Saya setuju, inilah gunanya server build. Kontrol sumber Anda adalah untuk mengelola kode sumber, bukan memastikan aplikasi Anda berfungsi.
Matius
4
Dalam kasus ekstrem, pembalasan mungkin menjadi alat notifikasi yang diperlukan saat melanggar pembangunan.
37
Setengah detik terlalu lambat? Itu penurunan dalam ember dibandingkan dengan memberikan satu pandangan terakhir pada apa yang sedang dilakukan dan kemudian memikirkan dan mengetik komentar komit yang sesuai.
Doval
5
@Doval: perbedaannya adalah ketika Anda memberikan satu pandangan terakhir atau memikirkan komentar, Anda proaktif , dan karenanya, Anda tidak menunggu. Ini bukan waktu yang Anda habiskan sebelum mengetik karakter terakhir di IDE Anda dan waktu ketika Anda dapat mulai mengetik lagi setelah komit selesai yang penting, tetapi berapa lama Anda menunggu. Itu sebabnya kompiler harus cepat; tidak masalah bahwa Anda menghabiskan lebih banyak waktu membaca dan menulis kode, karena ketika Anda melakukannya, Anda tidak menunggu, sedangkan ketika kode dikompilasi, Anda tergoda untuk beralih ke aktivitas yang berbeda.
Arseni Mourzenko
10
@ Thomas: ini bukan tentang gangguan, tetapi tentang gangguan. Dengan cara yang sama, 100 ms. "memiliki dampak yang terukur" pada bagaimana orang menggunakan situs web. Pola yang sama di sini: 100 ms. tidak seberapa dibandingkan dengan waktu yang Anda habiskan menonton video YouTube atau memulai PC Anda: secara sadar , Anda tidak akan melihat perbedaan antara 600 ms. dan 700 ms. menunda. Tetapi secara tidak sadar, itu mempengaruhi perilaku Anda. Dengan cara yang sama, melakukan sedikit lebih lambat membuat Anda enggan melakukan lebih awal dan sering.
Arseni Mourzenko
41

Biarkan saya menjadi orang yang tidak setuju dengan sesama penjawab saya.

Ini dikenal sebagai Gated Check-in di dunia TFS, dan saya harapkan di tempat lain. Ketika Anda mencoba untuk masuk ke cabang dengan check-in yang terjaga keamanannya, set rak dikirim ke server, yang memastikan perubahan Anda meningkat dan tes unit yang ditentukan (baca: semua) lulus. Jika tidak, itu memberi tahu Anda bahwa Anda adalah monyet jahat yang merusak bangunan. Jika ya, perubahannya masuk ke kontrol sumber (yay!).

Dalam pengalaman saya, check-in yang terjaga keamanannya adalah salah satu proses paling penting untuk pengujian unit yang sukses - dan dengan ekstensi, kualitas perangkat lunak.

Mengapa?

  • Karena check-in yang terjaga keamanannya memaksa orang untuk memperbaiki tes yang rusak. Begitu tes yang rusak menjadi sesuatu yang dapat dilakukan orang daripada harus dilakukan, tes itu menjadi tidak diprioritaskan oleh insinyur yang malas dan / atau orang bisnis yang memaksa.
    • Semakin lama tes rusak, semakin sulit (dan lebih mahal) untuk memperbaikinya.
  • Karena begitu orang harus menjalankan tes daripada harus menjalankan tes, menjalankan tes dihindari oleh insinyur yang malas / pelupa dan / atau pebisnis yang memaksa.
  • Karena begitu unit test memengaruhi waktu komitmen Anda, orang - orang benar-benar mulai peduli untuk membuat tes unit tes mereka. Masalah kecepatan. Masalah daya reproduksi. Masalah keandalan. Masalah isolasi.

Dan tentu saja, ada manfaat yang Anda bawa pada awalnya - ketika Anda memiliki gerbang masuk check-in dan serangkaian tes yang solid, setiap perubahan tunggal adalah "stabil". Anda menyimpan semua overhead (dan potensi kesalahan) dari "kapan bangunan bagus terakhir?" - semua bangunan cukup baik untuk dikembangkan.

Ya, butuh waktu untuk membangun dan menjalankan tes. Dalam pengalaman saya 5-10 menit untuk aplikasi C # berukuran bagus dan ~ 5k unit test. Dan saya tidak peduli tentang itu. Ya, orang harus sering check-in. Tetapi mereka juga harus sering memperbarui tugas mereka, atau memeriksa email mereka, atau mendapatkan kopi atau lusinan hal-hal "tidak bekerja pada kode" lainnya yang membentuk pekerjaan seorang insinyur perangkat lunak untuk mengisi waktu itu. Memeriksa kode buruk jauh lebih mahal daripada 5-10 menit.

Telastyn
sumber
3
+1 Saya ingin menambahkan, bahwa banyak proyek open source memiliki perbedaan yang jelas antara kontribusi dan komitmen. Alasannya sangat mirip dengan alasan adanya check-in yang terjaga keamanannya.
JensG
Satu masalah signifikan dengan gated check-in adalah menghambat pemecahan masalah kolaboratif dari kode yang sulit. Ini bahkan lebih signifikan dengan tim yang didistribusikan.
CuriousRabbit
2
@CuriousRabbit - bagaimana menurut Anda? Orang jarang berkomitmen secara kolaboratif bahkan jika mereka bekerja secara kolaboratif. Kalau tidak, rak atau cabang tugas yang tidak bertanggal bekerja baik untuk itu sementara tidak menghalangi anggota tim lainnya.
Telastyn
@ Telastyn– Shelvesets adalah istilah baru untuk saya. Saya berpendapat bahwa ini adalah opsi MS VS, yang tidak ada pilihan untuk sejumlah besar proyek. Di bidang pengembangan aplikasi seluler, VS adalah non-pemain.
CuriousRabbit
3
@CuriousRabbit - benarkah? Sebuah tim yang mendistribusikan lebih dari 17 jam lebih peduli menunggu 10 menit untuk komit daripada kemungkinan bangunan yang rusak saat pihak yang melanggar sedang tidur? Sepertinya ... Kurang optimal.
Telastyn
40

Komit harus berjalan cepat. Ketika saya mengkomit beberapa kode saya ingin itu didorong ke server. Saya tidak ingin menunggu beberapa menit saat menjalankan serangkaian tes. Saya bertanggung jawab untuk apa yang saya push ke server dan tidak perlu ada yang menjaga saya dengan komit.

Yang mengatakan, begitu sampai ke server, itu harus dianalisis, unit diuji, dan dibangun segera (atau dalam jangka waktu singkat). Ini akan mengingatkan saya pada fakta bahwa unit test rusak, atau tidak dikompilasi, atau saya membuat kekacauan yang ditunjukkan oleh alat analisis statis yang tersedia. Semakin cepat ini dilakukan (build dan analisis), semakin cepat umpan balik saya dan semakin cepat saya bisa memperbaikinya (pikiran belum sepenuhnya ditukar keluar dari otak saya).

Jadi tidak, jangan melakukan tes dan itu di kait komit pada klien. Jika Anda harus, letakkan di server di komit pos (karena Anda tidak memiliki server CI) atau di server build CI dan beri tahu saya dengan tepat jika ada masalah dengan kode tersebut. Tetapi jangan menghalangi komit untuk terjadi sejak awal.

Saya juga harus menunjukkan bahwa dengan beberapa interpretasi dari Test Driven Development, seseorang harus memeriksa unit test yang rusak terlebih dahulu . Ini menunjukkan dan mendokumentasikan bug yang ada. Kemudian checkin nantinya adalah kode yang memperbaiki tes unit. Mencegah checkin apa pun hingga tes unit lulus akan mengurangi nilai efektif memeriksa dalam tes unit yang gagal mendokumentasikan masalah.

Terkait: Apakah saya harus memiliki unit test untuk cacat yang diketahui? dan Apa nilai memeriksa dalam gagal unit test?

Komunitas
sumber
2
Commits should run fast.apa manfaatnya? Saya ingin tahu karena saat ini kami menggunakan checkin yang terjaga keamanannya. Biasanya checkin saya adalah penumpukan sekitar satu jam kerja, jadi menunggu 5 menit bukan masalah besar. Bahkan saya telah menemukan bahwa yang biasanya kali ketika saya berada di terburu-buru bahwa validasi membangun yang paling berguna untuk menangkap kesalahan konyol (sebagai akibat dari bergegas)
Justin
1
@ Justin. Tunggu lima menit adalah menunggu lima menit di mana pun itu. Seseorang tidak perlu mengeluarkan pedang nerf setiap kali Anda melakukan komit. Dan tidak jarang bagi saya untuk membagi satu atau lebih pekerjaan menjadi beberapa komit yang masing-masing unit konseptual satu sama lain - "komit kode servis sisanya" diikuti oleh "komit kode untuk halaman klien yang dilayani" sebagai dua komit terpisah (Belum lagi tweak css sebagai komit lain). Jika masing-masing membutuhkan waktu 5 menit untuk menjalankan, 1/6 dari waktu saya dihabiskan untuk menunggu tes. Ini akan mengarah pada komitmen rollup yang lebih besar yang lebih sulit untuk melacak bug.
5 menit menunggu untuk menjalankan tes unit? Saya merasa proyek yang sedang Anda kerjakan harus dipecah menjadi komponen yang lebih kecil.
user441521
@ Hanya catching silly mistakes (as a result of rushing)tepat. terburu-buru secara umum adalah praktik buruk dalam rekayasa perangkat lunak. Robert C. Martin merekomendasikan untuk menulis kode seperti melakukan operasi youtube.com/watch?v=p0O1VVqRSK0
Jerry Joseph
10

Pada prinsipnya, saya pikir masuk akal untuk mencegah orang membuat perubahan pada garis utama yang melanggar pembangunan. Yaitu, proses untuk membuat perubahan pada cabang utama repositori Anda harus memastikan bahwa semua tes masih lulus. Menghancurkan bangunan itu terlalu mahal dalam hal waktu yang hilang bagi semua insinyur di proyek untuk melakukan hal lain.

Namun, solusi khusus dari kait komit bukanlah rencana yang baik.

  1. Pengembang harus menunggu tes berjalan saat melakukan. Jika pengembang harus menunggu di stasiun kerjanya untuk semua tes untuk lulus, Anda sudah membuang-buang waktu insinyur yang berharga. Insinyur harus dapat pindah ke tugas berikutnya, bahkan jika dia harus beralih kembali karena tes akhirnya gagal.
  2. Pengembang mungkin ingin melakukan kode yang rusak di cabang. Dalam tugas yang lebih besar, versi pengembang kode mungkin menghabiskan banyak waktu tidak dalam keadaan lewat. Jelas, menggabungkan kode itu ke jalur utama akan sangat buruk. Tetapi agak penting bahwa pengembang masih dapat menggunakan kontrol versi untuk melacak kemajuannya.
  3. Kadang-kadang ada alasan bagus untuk melewati proses dan melewati tes.
Winston Ewert
sumber
2
# 1 dihilangkan dengan mengizinkan pengembang untuk check-in ke cabang pribadi atau repositori lokal. Hanya ketika pengembang menginginkan kode mereka di suatu tempat, pengembang lain dapat melihatnya bahwa tes unit perlu dijalankan. Seperti halnya # 1, # 2 dihilangkan dengan hanya kait ke cabang arus utama. # 3 dihilangkan oleh fakta bahwa A) Setiap fitur seperti itu dapat dinonaktifkan, meskipun itu merepotkan (dan harus merepotkan) dan B) Tes unit gagal individu dapat dinonaktifkan.
Brian
@ Brian, saya setuju sepenuhnya, Anda bisa membuat ini berfungsi. Tapi, coba lakukan dengan memblokir sisi server komit kait tidak akan berhasil.
Winston Ewert
poin bagus. Breaking the build is simply too costly in terms of lost time for all engineers on the projectSaya akan menyarankan menggunakan beberapa jenis alat notifikasi bangunan untuk menghindari semua insinyur akhirnya kehilangan waktu pada setiap bangunan yang rusak
Jerry Joseph
3

Tidak, Anda seharusnya tidak seperti yang ditunjukkan oleh jawaban lain.

Jika Anda ingin memiliki basis kode yang dijamin tidak memiliki tes yang gagal, Anda bisa mengembangkan pada cabang fitur dan melakukan tarik permintaan ke master. Kemudian Anda dapat menentukan prasyarat untuk menerima permintaan penarikan itu. Manfaatnya adalah Anda dapat mendorong dengan sangat cepat dan tes berjalan di latar belakang.

Yogu
sumber
2

Harus menunggu untuk membangun yang sukses dan menguji pada setiap komit ke cabang utama benar-benar mengerikan, saya pikir semua orang setuju tentang ini.

Tetapi ada cara lain untuk mencapai cabang utama yang konsisten. Berikut ini satu saran, sedikit mirip dengan alur check-in yang terjaga keamanannya di TFS, tetapi yang dapat digeneralisasikan untuk sistem kontrol versi apa pun dengan cabang, meskipun saya sebagian besar akan menggunakan istilah git:

  • Memiliki cabang pementasan yang Anda hanya dapat melakukan penggabungan antara cabang dev Anda dan cabang utama

  • Siapkan pengait yang memulai atau mengantri build dan menguji komit yang dilakukan pada staging branch, tetapi itu tidak membuat committer menunggu.

  • Pada build yang berhasil dan tes, secara otomatis membuat cabang utama maju jika up to date

    Catatan: jangan otomatis bergabung ke cabang utama, karena gabungan yang diuji, jika bukan gabungan ke depan dari sudut pandang cabang utama, mungkin gagal ketika digabungkan ke cabang utama dengan komit di antaranya

Sebagai konsekuensi:

  • Melarang manusia berkomitmen untuk cabang utama, secara otomatis jika Anda bisa, tetapi juga sebagai bagian dari proses resmi jika ada celah atau jika secara teknis tidak layak untuk menegakkan ini

    Paling tidak, Anda dapat memastikan tidak ada yang akan melakukannya secara tidak sengaja, atau tanpa niat jahat, begitu itu adalah aturan dasar. Anda seharusnya tidak berusaha melakukannya, selamanya.

  • Anda harus memilih antara:

    • Cabang pementasan tunggal, yang akan membuat penggabungan yang berhasil benar-benar gagal jika gabungan yang sebelumnya belum dibangun dan yang gagal diuji gagal

      Paling tidak, Anda akan tahu gabungan mana yang gagal dan ada orang yang memperbaikinya, tetapi gabungan di antaranya tidak dapat dilacak secara sepele (oleh sistem kontrol versi) untuk hasil pembuatan dan pengujian lebih lanjut.

      Anda dapat melihat anotasi file (atau menyalahkan), tetapi terkadang perubahan pada file (misalnya konfigurasi) akan menghasilkan kesalahan di tempat yang tidak terduga. Namun, ini adalah peristiwa yang agak jarang.

    • Beberapa cabang pementasan, yang akan memungkinkan penggabungan sukses yang tidak bertentangan untuk sampai ke cabang utama

      Bahkan dalam hal beberapa cabang pementasan lainnya memiliki gabungan gagal yang tidak bertentangan . Keterlacakan sedikit lebih baik, setidaknya kasus satu merger tidak mengharapkan perubahan yang mempengaruhi dari merger lainnya. Tetapi sekali lagi, ini cukup langka untuk tidak perlu dikhawatirkan setiap hari atau setiap minggu.

      Untuk memiliki penggabungan non-konflik sebagian besar waktu, penting untuk membagi cabang pementasan secara masuk akal, misalnya per tim, per lapisan, atau per komponen / proyek / sistem / solusi (siapa pun nama Anda).

      Jika cabang utama sementara itu diteruskan ke penggabungan lain, Anda harus menggabungkan lagi. Mudah-mudahan, ini bukan masalah dengan gabungan yang tidak saling bertentangan atau dengan sangat sedikit konflik.

Dibandingkan dengan check-in yang terjaga keamanannya, keuntungan di sini adalah Anda memiliki jaminan cabang utama yang berfungsi, karena cabang utama hanya diperbolehkan untuk maju, tidak untuk secara otomatis menggabungkan perubahan Anda dengan apa pun yang dilakukan di antaranya. Jadi poin ketiga adalah perbedaan esensial.

acelent
sumber
Tetapi tujuan memiliki cabang kerja bukan (biasanya) untuk memastikan Anda memiliki rilis stabil, tetapi untuk mengurangi meronta-ronta yang disebabkan oleh pengembang bekerja sama dalam kode yang sama.
Telastyn
Tidak jika Anda memiliki repo besar dengan tim-tim besar yang didistribusikan secara global. Misalnya Microsoft menggunakan pendekatan serupa yang lebih berlapis dengan Windows.
acelent
2

Saya lebih suka "lulus tes unit" menjadi gerbang untuk mengirimkan kode. Namun, untuk membuatnya bekerja, Anda perlu beberapa hal.

Anda akan membutuhkan kerangka kerja yang menyimpan artefak.

Anda akan memerlukan kerangka uji yang menyimpan status pengujian dari pengujian berjalan (berhasil), dengan artefak yang diberikan.

Dengan begitu, check-in dengan lulus tes unit akan cepat (cross-check dari sumber ke artefak yang dibangun ketika pengembang memeriksa tes sebelum check-in), yang dengan tes unit gagal akan diblokir dan pengembang yang mudah lupa untuk memeriksa build sebelum melakukan akan didorong untuk mengingat melakukannya lain kali, karena siklus kompilasi-dan-tes panjang.

Vatine
sumber
1

Saya akan mengatakan itu tergantung pada proyek dan ruang lingkup tes otomatis yang dijalankan pada "komit".

Jika tes yang ingin Anda jalankan di pemicu check-in benar-benar cepat, atau jika alur kerja pengembang akan memaksa beberapa pekerjaan administratif setelah check-in seperti itu, saya pikir itu tidak terlalu menjadi masalah dan memaksa para pengembang untuk hanya memeriksa dalam hal-hal yang benar-benar menjalankan tes paling dasar. (Saya berasumsi Anda hanya akan menjalankan tes paling mendasar pada pemicu seperti itu.)

Dan saya pikir, kecepatan / alur kerja memungkinkan, itu adalah hal yang baik untuk tidak mendorong perubahan ke pengembang lain yang gagal dalam tes - dan Anda hanya tahu jika mereka gagal jika Anda menjalankannya.

Anda menulis "komit ... ke cabang jauh" dalam pertanyaan, yang akan menyiratkan kepada saya bahwa ini adalah (a) bukan sesuatu yang dilakukan dev setiap beberapa menit, jadi menunggu kecil mungkin dapat diterima dengan sangat baik, dan (b) bahwa setelah komit semacam itu perubahan kode dapat berdampak pada pengembang lain, jadi pemeriksaan tambahan mungkin dalam urutan.

Saya bisa setuju dengan jawaban lain pada "jangan bikin ibu jari Anda sambil menunggu" untuk operasi seperti itu.

Martin Ba
sumber
1

Komitmen yang rusak tidak boleh diizinkan di bagasi , karena bagasi adalah yang mungkin diproduksi. Jadi, Anda perlu memastikan ada gateway yang harus dilewati sebelum berada di bagasi . Namun, komit yang rusak dapat benar-benar baik dalam repo selama tidak berada di bagasi.

Di sisi lain, mengharuskan pengembang untuk menunggu / memperbaiki masalah sebelum mendorong perubahan ke repositori memiliki sejumlah kelemahan.

Beberapa contoh:

  • Dalam TDD, adalah umum untuk melakukan dan mendorong pengujian yang gagal untuk fitur-fitur baru sebelum mulai mengimplementasikan fitur tersebut
  • Hal yang sama berlaku untuk melaporkan bug dengan melakukan dan mendorong tes yang gagal
  • Mendorong kode yang tidak lengkap memungkinkan 2 orang atau lebih untuk mengerjakan fitur secara paralel dengan mudah
  • Infrastruktur CI Anda dapat memverifikasi waktunya, tetapi pengembang tidak harus menunggu
tkruse
sumber