Apakah praktik yang buruk untuk menegakkan perintah eksekusi untuk pengujian unit?

84

Saya menulis tes untuk sebuah proyek yang terdiri dari beberapa submodula. Setiap test case yang saya tulis berjalan independen satu sama lain dan saya menghapus semua data antar test.

Meskipun tes berjalan secara independen, saya mempertimbangkan untuk menegakkan perintah eksekusi, karena beberapa kasus memerlukan lebih dari satu submodule. Sebagai contoh, sebuah submodule menghasilkan data, dan yang lainnya menjalankan kueri pada data. Jika submodule yang menghasilkan data mengandung kesalahan, tes untuk submodule kueri juga akan gagal, bahkan jika submodule itu sendiri berfungsi dengan baik.

Saya tidak dapat bekerja dengan data dummy, karena fungsi utama yang saya uji adalah koneksi ke server kotak hitam, yang hanya mendapatkan data dari submodule pertama.

Dalam hal ini, apakah boleh untuk menegakkan perintah eksekusi untuk tes atau itu praktik yang buruk? Saya merasa seperti ada bau dalam pengaturan ini, tetapi saya tidak dapat menemukan cara yang lebih baik.

sunting: pertanyaannya adalah dari Bagaimana menyusun tes di mana satu tes adalah setup tes lain? karena tes "sebelumnya" bukan pengaturan, tetapi menguji kode yang melakukan pengaturan.

Ali Rasim Kocal
sumber
123
Jika Anda menguji koneksi ke server jauh, maka mereka secara definisi bukan tes unit.
Telastyn
9
Jawaban pertama membingungkan saya di sini karena dalam judul Anda, Anda berkata "Apakah itu praktik yang buruk?" dan dalam ringkasan pertanyaan Anda, Anda menulis "tidak apa-apa?" Siapa pun yang menjawab ya atau tidak akan membingungkan salah satu dari mereka!
Liath
8
Kedengarannya seperti Anda sedang membuat serangkaian tes integrasi. Bahkan untuk satu tes tidak harus bergantung pada tes lain.
Pelican Terbang Rendah
17
Jika pesanan penting maka Anda mungkin melakukan kesalahan.
Mark Rogers

Jawaban:

236

Saya tidak dapat bekerja dengan data dummy, karena fungsi utama yang saya uji adalah koneksi ke server kotak hitam, yang hanya mendapatkan data dari submodule pertama.

Ini adalah bagian penting bagi saya. Anda dapat berbicara tentang "unit test" dan mereka "berjalan secara independen satu sama lain", tetapi semuanya terdengar seperti mereka bergantung pada server jarak jauh ini dan bergantung pada "sub modul pertama". Jadi semuanya terdengar sangat erat dan tergantung pada kondisi eksternal. Dengan demikian, Anda sebenarnya sedang menulis tes integrasi. Menjalankan tes-tes itu dalam urutan tertentu adalah sangat normal karena sangat tergantung pada faktor-faktor eksternal. Uji coba yang diperintahkan, dengan opsi untuk keluar lebih awal dari uji coba jika ada masalah yang benar-benar dapat diterima untuk uji integrasi.

Tapi, itu juga layak untuk mengambil melihat segar pada struktur aplikasi Anda. Mampu mengolok-olok submodul pertama dan server eksternal akan berpotensi memungkinkan Anda untuk menulis unit test yang benar untuk semua submodul lainnya.

David Arno
sumber
14
Belum lagi beberapa tes harus secara khusus memeriksa bahwa perilaku yang diharapkan terjadi ketika server jauh tidak tersedia.
Alexander
2
Atau, mungkin, Anda sebenarnya bermaksud menulis tes integrasi, dan dengan demikian mengejek data tidak akan mencapai apa yang Anda coba capai dengan tes ini.
Guy Schalnat
10
Masalahnya adalah kemungkinan besar bahwa Junit memiliki "unit" dalam namanya.
Thorbjørn Ravn Andersen
7
@ ThorbjørnRavnAndersen Persis. Orang secara alami menulis tes integrasi, bukan tes unit, karena tes integrasi keduanya jauh lebih berguna dan jauh lebih sulit untuk menulis daripada tes unit "nyata". Tetapi karena kerangka pengujian yang populer dinamai sesuai dengan konsep unit test, istilah tersebut telah dikooptasi dan menjadi berarti "pengujian otomatis" dalam bahasa modern.
Mason Wheeler
1
@MasonWheeler Atau bahkan dikooptasi oleh manajer non teknis berarti pengujian penerimaan.
TKK
32

Ya, itu praktik yang buruk.

Secara umum, tes unit dimaksudkan untuk menguji unit kode tunggal (misalnya fungsi tunggal berdasarkan status yang diketahui).

Saat Anda ingin menguji rangkaian peristiwa yang mungkin terjadi di alam liar, Anda menginginkan gaya uji yang berbeda, seperti tes integrasi. Ini bahkan lebih benar jika Anda bergantung pada layanan pihak ketiga.

Untuk menguji unit hal-hal seperti ini, Anda perlu mencari cara untuk menyuntikkan data dummy, misalnya mengimplementasikan antarmuka layanan data yang mencerminkan permintaan web tetapi mengembalikan data yang diketahui dari file data dummy lokal.

Paul
sumber
8
Sepakat. Saya pikir kebingungan ini berasal dari kenyataan bahwa banyak orang memiliki gagasan bahwa tes integrasi harus end-to-end, dan menggunakan "unit test" untuk merujuk pada tes apa pun yang hanya menguji satu lapisan .
autophage
8
@autophage: Pasti setuju dengan ini. Bahkan saya sangat setuju dengan itu sehingga saya secara teratur menemukan diri saya jatuh ke dalam perangkap yang sama meskipun setuju bahwa itu adalah perangkap 😂
Lightness Races in Orbit
16

Perintah pelaksanaan yang dipaksakan yang Anda usulkan hanya masuk akal jika Anda juga membatalkan pengujian setelah kegagalan pertama.

Membatalkan uji coba pada kegagalan pertama berarti bahwa setiap uji coba hanya dapat mengungkap satu masalah dan itu tidak dapat menemukan masalah baru sampai semua masalah sebelumnya telah diperbaiki. Jika tes pertama yang dijalankan menemukan masalah yang membutuhkan waktu satu bulan untuk diperbaiki, maka selama bulan itu secara efektif tidak ada tes yang akan dijalankan.

Jika Anda tidak membatalkan pengujian yang dijalankan pada kegagalan pertama, maka perintah eksekusi yang dipaksakan tidak akan memberi Anda apa pun karena setiap tes yang gagal perlu diselidiki pula. Bahkan jika hanya untuk mengkonfirmasi bahwa pengujian pada submodule kueri gagal karena kegagalan yang juga diidentifikasi pada data yang menghasilkan submodule.

Saran terbaik yang bisa saya berikan adalah menulis tes sedemikian rupa sehingga mudah untuk mengidentifikasi kapan kegagalan dalam ketergantungan menyebabkan tes gagal.

Bart van Ingen Schenau
sumber
7

Aroma yang Anda maksudkan adalah penerapan serangkaian kendala dan aturan yang salah pada pengujian Anda.

Unit Test sering bingung dengan "pengujian otomatis", atau "pengujian otomatis oleh seorang programmer".

Tes Unit harus kecil, independen, dan cepat.

Beberapa orang salah membaca ini sebagai "tes otomatis yang ditulis oleh seorang programmer harus kecil independen dan cepat" . Tapi itu hanya berarti jika tes Anda tidak kecil, independen, dan cepat, mereka tidak Unit Pengujian, dan karena itu beberapa aturan untuk Unit Pengujian tidak harus, tidak bisa, atau tidak harus mengajukan permohonan untuk tes Anda. Contoh sepele: Anda harus menjalankan Tes Unit setelah setiap build, yang tidak boleh Anda lakukan untuk tes otomatis yang tidak cepat.

Meskipun tes Anda bukan Tes Unit berarti Anda dapat melewati satu aturan dan diizinkan untuk memiliki saling ketergantungan di antara tes, Anda juga menemukan bahwa ada aturan lain yang mungkin Anda lewatkan dan perlu diperkenalkan kembali - sesuatu untuk ruang lingkup pertanyaan lain .

Peter
sumber
6

Seperti disebutkan di atas, apa yang Anda jalankan tampaknya merupakan tes integrasi, namun Anda menyatakan bahwa:

Sebagai contoh, sebuah submodule menghasilkan data, dan yang lainnya menjalankan kueri pada data. Jika submodule yang menghasilkan data mengandung kesalahan, tes untuk submodule kueri juga akan gagal, bahkan jika submodule itu sendiri berfungsi dengan baik.

Dan ini mungkin tempat yang baik untuk memulai refactoring. Modul yang menjalankan kueri pada data tidak boleh bergantung pada implementasi konkret dari modul (data pembangkit) pertama. Alih-alih akan lebih baik untuk menyuntikkan antarmuka yang berisi metode untuk mendapatkan data itu dan ini kemudian dapat dipermainkan untuk menguji kueri.

misalnya

Jika Anda memiliki:

class Queries {

    int GetTheNumber() {
        var dataModule = new Submodule1();
        var data = dataModule.GetData();
        return ... run some query on data
    }
}

Alih-alih lebih suka:

interface DataModule {
    Data GetData();
}


class Queries {

    IDataModule _dataModule;

    ctor(IDataModule dataModule) {
       _dataModule = dataModule;
    }

    int GetTheNumber() {
        var data = _dataModule.GetData();
        return ... run some query on data
    }
}

Ini menghapus ketergantungan dari kueri pada sumber data Anda dan memungkinkan Anda untuk mengatur tes unit yang mudah diulang untuk skenario tertentu.

Padi
sumber
6

Jawaban lain menyebutkan bahwa tes pemesanan buruk (yang memang benar sebagian besar waktu), tetapi ada satu alasan bagus untuk menegakkan pesanan pada pelaksanaan tes: pastikan tes lambat Anda (yaitu, tes integrasi) berjalan setelah tes cepat Anda (tes yang tidak bergantung pada sumber daya luar lainnya). Ini memastikan bahwa Anda melakukan lebih banyak tes lebih cepat, yang dapat mempercepat putaran umpan balik.

Mike Holler
sumber
2
Saya akan lebih cenderung menyelidiki mengapa unit test tertentu berjalan lambat daripada menegakkan perintah. Tes unit seharusnya cepat.
Robbie Dee
OP mengatakan dia tidak bisa bekerja dengan data tiruan untuk beberapa tes ini. Itu berarti semacam database hit, memperlambat semua tes (bahkan beberapa unit test sejati yang harus berjalan cepat secara alami). Jika ia memiliki tes lain yang tidak memerlukan klik database, mereka akan menjalankan urutan besarnya lebih cepat daripada apa pun yang membutuhkan hit disk atau jaringan.
Mike Holler
2
Anda berdua benar, saya pikir; Robbie benar bahwa unit test harus kecil dan cepat dan terisolasi dari dependensi sehingga pesanan tidak menjadi masalah dan pemesanan acak sering mendorong desain yang lebih baik dengan menegakkan independensi itu; dan Mike benar bahwa menjalankan tes lebih cepat terlebih dahulu sangat, sangat bagus untuk tes integrasi . Seperti dalam jawaban di atas, bagian dari masalah adalah terminologi tes unit vs integrasi.
WillC
@ MikeHoller Maka mereka bukan unit test. Seharusnya tidak ada kebingungan tentang apa tes unit .
Robbie Dee
@RobbieDee Saya hanya menggunakan terminologi yang digunakan OP. Saya mengerti bahwa ini bukan tes unit yang benar. Jika Anda ingin bertengkar tentang terminologi, tampilkan dengan OP. (maka dari itu mengapa saya mengklarifikasi dengan "unit test sejati" dalam komentar saya sebelumnya ")
Mike Holler