Bukankah tes unit harus menggunakan metode saya sendiri?

83

Hari ini saya menonton video " JUnit basics" dan penulis mengatakan bahwa ketika menguji metode yang diberikan dalam program Anda, Anda tidak boleh menggunakan metode Anda sendiri dalam proses.

Untuk lebih spesifik, dia berbicara tentang pengujian beberapa metode pembuatan catatan yang mengambil nama dan nama belakang untuk argumen, dan itu digunakan untuk membuat catatan dalam tabel yang diberikan. Tetapi dia mengklaim bahwa dalam proses pengujian metode ini, dia tidak boleh menggunakan metode DAO lainnya untuk meminta basis data untuk memeriksa hasil akhir (untuk memeriksa bahwa catatan memang dibuat dengan data yang benar). Dia mengklaim bahwa untuk itu, dia harus menulis kode JDBC tambahan untuk menanyakan database dan memeriksa hasilnya.

Saya rasa saya mengerti semangat klaimnya: Anda tidak ingin uji kasus satu metode bergantung pada kebenaran metode lain (dalam hal ini, metode DAO), dan ini diselesaikan dengan menulis (lagi) validasi Anda sendiri / kode pendukung (yang harus lebih spesifik dan fokus, karenanya, kode lebih sederhana).

Meskipun demikian, suara-suara di dalam kepala saya mulai memprotes dengan argumen seperti duplikasi kode, upaya tambahan yang tidak perlu, dll. Maksud saya, jika kita menjalankan seluruh baterai uji, dan kita menguji semua metode publik kita secara menyeluruh (termasuk metode DAO dalam kasus ini), tidakkah seharusnya bolehkah hanya menggunakan beberapa metode tersebut saat menguji metode lain? Jika salah satu dari mereka tidak melakukan apa yang seharusnya, maka test case-nya akan gagal, dan kita dapat memperbaikinya dan menjalankan baterai tes lagi. Tidak perlu duplikasi kode (meskipun kode duplikatnya agak sederhana) atau usaha yang sia-sia.

Saya memiliki perasaan yang kuat tentang hal ini karena beberapa aplikasi Excel - VBA baru-baru ini yang saya tulis (teruji dengan benar berkat Rubberduck untuk VBA ), di mana menerapkan rekomendasi ini akan berarti banyak pekerjaan tambahan tambahan, tanpa manfaat yang dirasakan.

Bisakah Anda berbagi wawasan tentang hal ini?

carlossierra
sumber
79
Agak aneh untuk melihat unit test yang melibatkan database sama sekali
Richard Tingle
4
IMO tidak masalah untuk memanggil kelas lain IFF mereka cukup cepat. Mengejek apa pun yang harus masuk ke disk atau melalui jaringan. Tidak ada gunanya mengejek IMO kelas biasa.
RubberDuck
2
Punya tautan ke video ini?
candied_orange
17
" Teruji unit dengan benar berkat Rubberduck for VBA " - Anda Pak, baru saja membuat hari saya. Saya akan memperbaiki kesalahan ketik dan mengeditnya dari "RubberDuck" menjadi "Rubberduck", tetapi saya merasa ingin melakukan spammer dan menambahkan tautan ke rubberduckvba.com (Saya memiliki nama domain dan memiliki proyek bersama dengan @RubberDuck) - jadi saya hanya akan berkomentar di sini. Pokoknya itu luar biasa melihat orang-orang benar-benar menggunakan alat yang bertanggung jawab untuk sebagian besar malam tanpa tidur saya untuk bagian yang lebih baik dari dua tahun terakhir! =)
Mathieu Guindon
4
@ Mat'sMug dan RubberDuck Saya suka apa yang Anda lakukan dengan Rubberduck. Mohon pertahankan. Tentunya hidup saya lebih mudah karena itu (saya kebetulan melakukan banyak program kecil dan prototipe di Excel VBA). BTW, yang menyebutkan Rubberduck di posting saya hanya saya mencoba untuk bersikap baik kepada RubberDuck sendiri, yang pada gilirannya bagus untuk saya di sini di PE. :)
carlossierra

Jawaban:

186

Semangat klaimnya memang benar. Maksud unit test adalah untuk mengisolasi kode, mengujinya bebas dari ketergantungan, sehingga setiap perilaku yang salah dapat dengan cepat dikenali di mana ia terjadi.

Dengan mengatakan bahwa, pengujian unit adalah alat, dan itu dimaksudkan untuk melayani tujuan Anda, itu bukan altar untuk didoakan. Kadang-kadang itu berarti meninggalkan dependensi karena mereka bekerja cukup andal dan Anda tidak ingin repot mengejek mereka, kadang-kadang itu berarti beberapa unit test Anda sebenarnya cukup dekat jika tidak benar-benar tes integrasi.

Pada akhirnya Anda tidak akan dinilai, yang penting adalah produk akhir dari perangkat lunak yang diuji, tetapi Anda hanya harus berhati-hati ketika Anda menekuk aturan dan memutuskan kapan trade-off itu sepadan.

Apa namanya
sumber
117
Hore untuk pragmatisme.
Robert Harvey
6
Saya akan menambahkan bahwa tidak ada banyak keandalan seperti kecepatan yang merupakan masalah yang mengarah pada mematikan ketergantungan. Tes dalam mantra isolasi sangat menarik namun argumen ini sering dilewatkan.
Michael Durrant
4
"... unit testing adalah alat, dan itu dimaksudkan untuk melayani tujuanmu, itu bukan altar untuk didoakan." - ini!
Wayne Conrad
15
"bukan altar untuk didoakan" - pelatih TDD yang marah masuk!
Den
5
@ jpmc26: lebih buruk lagi Anda tidak ingin semua unit test Anda lulus karena mereka dengan benar menangani layanan web yang sedang down, yang merupakan perilaku yang benar dan benar, tetapi tidak pernah benar-benar menggunakan kode ketika sudah habis! Setelah Anda mematikannya, Anda bisa memilih apakah itu "naik" atau "turun" dan menguji keduanya.
Steve Jessop
36

Saya pikir ini sampai pada terminologi. Bagi banyak orang, "uji unit" adalah hal yang sangat spesifik, dan menurut definisi tidak dapat memiliki kondisi lulus / gagal yang tergantung pada kode apa pun di luar unit (metode, fungsi, dll.) Yang diuji. Ini akan termasuk interaksi dengan database.

Bagi yang lain, istilah "unit test" jauh lebih longgar, dan mencakup segala jenis pengujian otomatis, termasuk kode uji yang menguji bagian terintegrasi dari aplikasi.

Seorang purist uji (jika saya dapat menggunakan istilah itu) dapat menyebut bahwa tes integrasi , dibedakan dari tes unit dengan dasar bahwa tes tergantung pada lebih dari satu unit kode murni .

Saya menduga Anda menggunakan versi yang lebih longgar dari istilah "unit test", dan sebenarnya merujuk pada "tes integrasi".

Menggunakan definisi tersebut, Anda tidak boleh bergantung pada kode di luar unit yang sedang diuji dalam "unit test". Namun, dalam "tes integrasi", sangat masuk akal untuk menulis tes yang melatih beberapa kode tertentu dan kemudian memeriksa database untuk kriteria kelulusan.

Apakah Anda harus bergantung pada tes integrasi atau tes unit atau keduanya adalah topik diskusi yang jauh lebih besar.

Eric King
sumber
Anda benar pada kecurigaan Anda. Saya menyalahgunakan ketentuan dan saya dapat melihat sekarang bagaimana setiap jenis tes dapat ditangani dengan lebih tepat. Terima kasih!
carlossierra
11
"Bagi yang lain, istilah" uji unit "jauh lebih longgar" - selain dari yang lain, yang disebut "kerangka pengujian unit" adalah cara yang sangat mudah untuk mengatur dan menjalankan tes tingkat yang lebih tinggi ;-)
Steve Jessop
1
Daripada perbedaan "murni" vs "longgar", yang sarat dengan konotasi, saya sarankan perbedaannya adalah antara mereka yang melihat "unit", "dependensi", dll. Dari perspektif domain (mis. "Otentikasi" akan dihitung sebagai sebuah unit, "database" akan dihitung sebagai dependensi, dll.) vs. mereka yang melihatnya dari perspektif bahasa pemrograman (misalnya metode adalah unit, kelas adalah dependensi). Saya menemukan bahwa mendefinisikan apa yang dimaksud dengan frasa seperti "unit yang diuji" dapat mengubah argumen ("Anda salah!") Menjadi diskusi ("Apakah ini tingkat granularitas yang tepat?").
Warbo
1
@EricKing Tentu saja, bagi sebagian besar dari mereka yang berada dalam kategori pertama Anda, gagasan untuk melibatkan database sama sekali dalam unit test adalah laknat, apakah Anda menggunakan DAO Anda atau menekan database secara langsung.
Periata Breatta
1
@AmaniKilumanga Pertanyaannya pada dasarnya adalah "seseorang mengatakan saya tidak boleh melakukan hal ini dalam tes unit tapi saya melakukannya dalam tes unit dan saya pikir itu baik-baik saja. Apakah itu tidak apa-apa?" Dan jawaban saya adalah "Ya, tetapi kebanyakan orang akan menyebutnya tes integrasi daripada tes unit.". Sejauh pertanyaan Anda, saya tidak tahu apa yang Anda maksud dengan "bolehkah tes integrasi menggunakan metode kode produksi?".
Eric King
7

Jawabannya adalah ya dan tidak ...

Tes unik yang dilakukan secara terpisah adalah suatu keharusan mutlak karena memungkinkan Anda untuk meletakkan pekerjaan dasar bahwa kode tingkat rendah Anda berfungsi dengan tepat. Tetapi dalam pengkodean pustaka yang lebih besar, Anda juga akan menemukan area kode yang akan mengharuskan Anda memiliki tes yang melintasi unit.

Tes lintas-unit ini baik untuk cakupan kode dan saat menguji fungsionalitas ujung ke ujung, tetapi ada beberapa kelemahan yang harus Anda ketahui:

  • Tanpa tes terisolasi untuk mengkonfirmasi apa yang melanggar, tes "lintas unit" yang gagal akan membutuhkan pemecahan masalah tambahan untuk menentukan apa yang salah dengan kode Anda
  • Mengandalkan terlalu banyak tes lintas unit dapat membuat Anda keluar dari pola pikir kontrak yang harus selalu ada ketika menulis kode SOLID Object-Oriented. Tes terisolasi biasanya masuk akal karena unit Anda seharusnya hanya melakukan satu tindakan dasar saja.
  • Pengujian ujung ke ujung diinginkan tetapi dapat berbahaya jika suatu tes mengharuskan Anda untuk menulis ke database atau melakukan beberapa tindakan yang Anda tidak ingin terjadi dalam lingkungan produksi. Ini salah satu dari banyak alasan mengapa kerangka mengejek seperti Mockito sangat populer karena memungkinkan Anda untuk memalsukan objek dan meniru tes ujung ke ujung tanpa benar-benar mengubah sesuatu yang seharusnya tidak Anda lakukan.

Pada akhirnya Anda ingin memiliki keduanya .. banyak tes yang memerangkap fungsionalitas tingkat rendah dan beberapa yang menguji fungsionalitas ujung ke ujung. Fokus pada alasan mengapa Anda menulis tes di tempat pertama. Mereka ada di sana untuk memberi Anda keyakinan bahwa kode Anda berkinerja seperti yang Anda harapkan. Apa pun yang Anda perlu lakukan untuk mewujudkannya baik-baik saja.

Fakta yang menyedihkan tetapi benar adalah jika Anda menggunakan tes otomatis sama sekali maka Anda sudah memiliki kaki di banyak pengembang. Praktik pengujian yang baik adalah hal pertama yang meluncur ketika tim pengembangan dihadapkan dengan tenggat waktu yang sulit. Jadi, selama Anda tetap berpegang pada senjata Anda dan menulis tes unit yang merupakan refleksi bermakna tentang bagaimana kode Anda harus melakukan, saya tidak akan terobsesi pada seberapa "murni" tes Anda.

Lembab
sumber
4

Satu masalah dengan menggunakan metode objek lain untuk menguji suatu kondisi adalah bahwa Anda akan kehilangan kesalahan yang membatalkan satu sama lain. Lebih penting lagi, Anda kehilangan rasa sakit dari implementasi tes yang sulit, dan rasa sakit itu mengajarkan Anda sesuatu tentang kode yang mendasarinya. Tes yang menyakitkan sekarang berarti perawatan yang menyakitkan di kemudian hari.

Buat unit Anda lebih kecil, bagi kelas Anda, refactor, dan desain ulang hingga lebih mudah untuk menguji tanpa mengimplementasikan sisa objek Anda. Dapatkan bantuan jika Anda merasa kode atau tes Anda tidak dapat disederhanakan lebih lanjut. Cobalah untuk memikirkan kolega yang tampaknya selalu beruntung dan mendapatkan tugas yang mudah diuji dengan bersih. Minta bantuan padanya, karena itu bukan keberuntungan.

Karl Bielefeldt
sumber
1
Kunci di sini ada di unit. Jika Anda perlu melakukan panggilan ke prosedur dan proses lain, bagi saya itu bukan unit. Jika beberapa panggilan dilakukan dan beberapa langkah perlu divalidasi, maka jika itu adalah bagian besar dari kode, pecah menjadi beberapa bagian yang lebih kecil yang mencakup satu bagian logika. Biasanya, panggilan DB juga akan diejek atau dalam memori DB akan digunakan dalam tes unit untuk mengakses DB nyata dan perlu membatalkan data setelah tes.
dlb
1

Jika unit fungsionalitas yang diuji adalah 'adalah data yang disimpan terus-menerus dan dapat diambil kembali', maka saya akan memiliki tes uji unit yang - simpan ke database nyata, hancurkan objek yang memegang referensi ke database, kemudian panggil kode untuk mengambil objek kembali.

Menguji apakah catatan dibuat dalam database tampaknya berkaitan dengan rincian implementasi mekanisme penyimpanan daripada menguji unit fungsionalitas yang diekspos ke seluruh sistem.

Anda mungkin ingin memendekkan tes untuk meningkatkan kinerja menggunakan database tiruan, tetapi saya memiliki kontraktor yang melakukan hal itu dan meninggalkan pada akhir kontrak mereka dengan sistem yang lulus tes seperti itu, tetapi tidak benar-benar menyimpan apa pun dalam database antara reboot sistem.

Anda dapat berdebat apakah 'unit' dalam pengujian unit menunjukkan 'unit kode' atau 'unit fungsionalitas', fungsionalitas yang mungkin dibuat oleh banyak unit kode secara bersamaan. Saya tidak menemukan ini perbedaan yang berguna - pertanyaan yang akan saya ingat adalah 'apakah tes memberi tahu Anda tentang apakah sistem memberikan nilai bisnis', dan 'apakah tes rapuh jika implementasinya berubah?' Tes seperti yang dijelaskan bermanfaat ketika Anda TDD sistem - Anda belum menulis 'dapatkan objek dari database' namun jadi tidak dapat menguji unit fungsionalitas penuh - tetapi rapuh terhadap perubahan implementasi jadi saya akan hapus mereka setelah operasi penuh diuji.

Pete Kirkham
sumber
1

Roh itu benar.

Idealnya, dalam tes unit , Anda menguji unit (metode individu atau kelas kecil).

Idealnya, Anda akan mematikan seluruh sistem basis data. Yaitu, Anda akan menjalankan metode Anda di lingkungan yang dipalsukan dan pastikan bahwa itu memanggil DB API yang benar dalam urutan yang benar. Anda secara eksplisit dan positif tidak ingin menguji DB saat menguji salah satu metode Anda sendiri.

Manfaatnya banyak. Yang paling utama, tes menjadi sangat cepat karena Anda tidak perlu repot tentang pengaturan lingkungan DB yang benar dan mengembalikannya setelah itu.

Tentu saja, ini adalah tujuan mulia dalam setiap proyek perangkat lunak yang tidak melakukan hal ini sejak awal. Tapi itu adalah semangat pengujian unit .

Perhatikan bahwa ada tes lain, seperti tes fitur, tes perilaku, dll. Yang berbeda dari pendekatan ini - jangan bingung "pengujian" dengan "pengujian unit".

AnoE
sumber
"hanya pastikan bahwa ia memanggil DB API yang benar dalam urutan yang benar" - yeah, tentu. Hingga ternyata Anda salah membaca dokumentasi dan urutan yang benar yang seharusnya Anda gunakan benar-benar berbeda. Jangan mengejek sistem di luar kendali Anda.
Joker_vD
4
@ Joker_vD Itulah tujuan dari tes integrasi. Dalam tes unit, sistem eksternal mutlak harus diejek.
Ben Aaronson
1

Setidaknya ada satu alasan yang sangat penting untuk tidak menggunakan akses database langsung dalam tes unit Anda untuk kode bisnis yang berinteraksi dengan database: jika Anda mengubah implementasi database Anda, Anda harus menulis ulang semua tes unit tersebut. Ganti nama kolom, untuk kode Anda, Anda hanya perlu mengubah satu baris dalam definisi mapper data Anda. Namun, jika Anda tidak menggunakan mapper data saat pengujian, maka Anda juga harus mengubah setiap pengujian unit tunggal yang merujuk pada kolom ini . Ini bisa berubah menjadi pekerjaan yang luar biasa, terutama untuk perubahan yang lebih kompleks yang kurang bisa diterima dan diganti.

Juga, menggunakan data mapper Anda sebagai mekanisme abstrak daripada berbicara langsung dengan basis data membuatnya lebih mudah untuk menghapus ketergantungan pada basis data sepenuhnya , yang mungkin tidak relevan sekarang, tetapi ketika Anda mendapatkan hingga ribuan unit test dan semuanya Memukul database, Anda akan berterima kasih bahwa Anda dapat dengan mudah refactor mereka untuk menghapus ketergantungan itu karena test suite Anda akan turun dari mengambil menit untuk menjalankan ke mengambil detik, yang dapat memiliki manfaat besar pada produktivitas Anda.

Pertanyaan Anda menunjukkan bahwa Anda berpikir di jalur yang benar. Seperti yang Anda duga, unit test juga merupakan kode. Sama pentingnya untuk membuatnya dapat dipertahankan dan mudah beradaptasi dengan perubahan di masa mendatang seperti halnya untuk sisa basis kode Anda. Berusahalah untuk membuatnya mudah dibaca dan untuk menghilangkan duplikasi, dan Anda akan memiliki test suite yang jauh lebih baik untuk itu. Dan test suite yang bagus adalah yang digunakan. Dan test suite yang digunakan membantu menemukan kesalahan, sedangkan yang tidak digunakan tidak berharga.

Periata Breatta
sumber
1

Pelajaran terbaik yang saya pelajari ketika belajar tentang pengujian unit dan pengujian integrasi adalah untuk tidak menguji metode, tetapi menguji perilaku. Dengan kata lain, apa yang dilakukan objek ini?

Ketika saya melihatnya seperti itu, metode yang mempertahankan data dan metode lain yang membacanya kembali mulai dapat diuji. Jika Anda menguji metode secara khusus, tentu saja, Anda berakhir dengan tes untuk setiap metode secara terpisah seperti:

@Test
public void canSaveData() {
    writeDataToDatabase();
    // what can you assert - the only expectation you can have here is that an exception was not thrown.
}

@Test
public void canReadData() {
    // how do I even get data in there to read if I cannot call the method which writes it?
}

Masalah ini terjadi karena perspektif metode pengujian. Jangan menguji metode. Uji perilaku. Apa perilaku kelas WidgetDao? Itu tetap ada widget. Oke, bagaimana Anda memverifikasi itu tetap ada widget? Nah, apa definisi dari kegigihan? Artinya ketika Anda menulisnya, Anda dapat membacanya kembali. Jadi baca + tulis bersama menjadi ujian, dan menurut saya, ujian lebih bermakna.

@Test
public void widgetsCanBeStored() {
    Widget widget = new Widget();
    widget.setXXX.....
    // blah

    widgetDao.storeWidget(widget);
    Widget stored = widgetDao.getWidget(widget.getWidgetId());
    assertEquals(widget, stored);
}

Itu adalah tes logis, kohesif, dapat diandalkan, dan menurut saya, yang berarti.

Jawaban lain memfokuskan betapa pentingnya isolasi, debat pragmatis versus realistis, dan apakah suatu unit test mungkin atau tidak menanyakan database. Mereka tidak benar-benar menjawab pertanyaan itu.

Untuk menguji apakah sesuatu dapat disimpan, Anda harus menyimpannya dan kemudian membacanya kembali. Anda tidak dapat menguji apakah ada sesuatu yang disimpan jika Anda tidak diizinkan untuk membacanya. Jangan menguji penyimpanan data secara terpisah dari pengambilan data. Anda akan berakhir dengan tes yang tidak memberi tahu Anda apa-apa.

Brandon
sumber
Pendekatan yang sangat mendalam, dan seperti yang Anda katakan, saya pikir Anda benar-benar memukul salah satu keraguan inti yang saya miliki. Terima kasih!
carlossierra
0

Salah satu contoh kasus kegagalan yang Anda ingin tangkap, adalah bahwa objek yang diuji menggunakan lapisan caching tetapi gagal untuk mempertahankan data sesuai kebutuhan. Kemudian jika Anda meminta objek itu akan mengatakan "yup, saya punya nama dan alamat baru", tetapi Anda ingin tes gagal karena belum benar-benar melakukan apa yang seharusnya.

Atau (dan mengabaikan pelanggaran tanggung jawab tunggal), anggaplah diperlukan untuk mempertahankan versi string UTF-8 yang dikodekan ke bidang berorientasi byte, tetapi sebenarnya tetap menggunakan Shift JIS. Beberapa komponen lain akan membaca basis data dan mengharapkan untuk melihat UTF-8, karena itu diperlukan. Kemudian bolak-balik melalui objek ini akan melaporkan nama dan alamat yang benar karena itu akan mengubahnya kembali dari Shift JIS, tetapi kesalahan tidak terdeteksi oleh pengujian Anda. Mudah-mudahan akan terdeteksi oleh beberapa tes integrasi nanti, tetapi inti dari tes unit adalah untuk menangkap masalah lebih awal, dan tahu persis komponen apa yang bertanggung jawab.

Jika salah satu dari mereka tidak melakukan apa yang seharusnya, maka test case-nya akan gagal dan kita dapat memperbaikinya dan menjalankan baterai tes lagi.

Anda tidak dapat menganggap ini, karena jika Anda tidak hati-hati Anda menulis serangkaian tes yang saling bergantung. "Apakah itu menyelamatkan?" tes memanggil metode simpan yang sedang diuji, dan kemudian metode memuat untuk mengonfirmasi bahwa metode itu disimpan. "Apakah dimuat?" test memanggil metode save untuk mengatur fixture test dan kemudian load method yang diuji untuk memeriksa hasilnya. Kedua pengujian bergantung pada kebenaran metode yang tidak mereka uji, yang berarti bahwa keduanya tidak benar-benar menguji kebenaran metode yang diuji.

Petunjuk bahwa ada masalah di sini, adalah bahwa dua tes yang seharusnya menguji unit yang berbeda sebenarnya melakukan hal yang sama . Mereka berdua memanggil seorang setter diikuti oleh seorang pengambil, kemudian memeriksa hasilnya adalah nilai asli. Tetapi Anda ingin menguji bahwa setter tetap menggunakan data, bukan bahwa pasangan setter / pengambil bekerja bersama-sama. Jadi Anda tahu ada sesuatu yang salah, Anda hanya perlu mencari tahu apa dan memperbaiki tes.

Jika kode Anda dirancang dengan baik untuk pengujian unit, maka setidaknya ada dua cara Anda dapat menguji apakah data telah benar-benar bertahan dengan metode yang diuji:

  • tiruan antarmuka basis data, dan minta tiruan Anda mencatat fakta bahwa fungsi yang tepat telah dipanggil, dengan nilai yang diharapkan. Ini menguji metode melakukan apa yang seharusnya, dan merupakan tes unit klasik.

  • berikan itu basis data aktual dengan maksud yang persis sama , untuk merekam apakah data telah bertahan dengan benar atau tidak. Tetapi alih-alih memiliki fungsi mengejek yang hanya mengatakan "yup, saya mendapat data yang tepat", tes Anda membaca kembali dari database secara langsung dan mengonfirmasi itu benar. Ini mungkin bukan tes semurni mungkin, karena seluruh mesin basis data adalah hal yang cukup besar untuk digunakan untuk menulis tiruan yang dimuliakan, dengan lebih banyak kesempatan saya melihat beberapa kehalusan yang membuat lulus ujian meskipun ada sesuatu yang salah (jadi misalnya saya tidak boleh menggunakan koneksi database yang sama untuk membaca seperti yang digunakan untuk menulis, karena saya mungkin melihat transaksi tidak berkomitmen). Tapi itu menguji hal yang benar, dan setidaknya Anda tahu persis mengimplementasikan seluruh antarmuka basis data tanpa harus menulis kode tiruan apa pun!

Jadi itu hanyalah detail implementasi tes apakah saya membaca data dari database tes oleh JDBC atau apakah saya mengejek database. Either way intinya adalah bahwa saya dapat menguji unit lebih baik dengan mengisolasinya daripada saya dapat jika saya membiarkannya berkonspirasi dengan metode yang salah lainnya di kelas yang sama agar terlihat benar bahkan ketika ada sesuatu yang salah. Oleh karena itu saya ingin menggunakan sarana yang mudah untuk memeriksa apakah data yang benar tetap ada, selain mempercayai komponen yang metodenya saya uji.

Jika kode Anda tidak dirancang dengan baik untuk pengujian unit, maka Anda mungkin tidak punya pilihan, karena objek yang metode yang ingin Anda uji mungkin tidak menerima database sebagai ketergantungan yang disuntikkan. Dalam hal ini diskusi tentang cara terbaik untuk mengisolasi unit yang sedang diuji, berubah menjadi diskusi tentang seberapa dekat mungkin untuk mengisolasi unit yang sedang diuji. Tapi kesimpulannya sama. Jika Anda dapat menghindari konspirasi di antara unit yang salah maka Anda melakukannya, tergantung pada waktu yang tersedia dan apa pun yang Anda pikirkan yang akan lebih efektif dalam menemukan kesalahan dalam kode.

Steve Jessop
sumber
0

Inilah yang saya suka lakukan. Ini hanya pilihan pribadi karena ini tidak akan berdampak pada hasil produk, hanya cara memproduksinya.

Ini tergantung pada kemungkinan untuk dapat menambahkan nilai tiruan dalam database Anda tanpa aplikasi yang Anda uji.

Katakanlah Anda memiliki dua tes: A - membaca basis data B - memasukkan ke dalam basis data (tergantung pada A)

Jika A lulus, maka Anda yakin bahwa hasil B akan tergantung pada bagian yang diuji dalam B dan bukan dependensi. Jika A gagal, Anda dapat memiliki negatif palsu untuk B. Kesalahannya mungkin dalam B atau A. Anda tidak bisa tahu pasti sampai A mengembalikan sukses.

Saya tidak akan mencoba menulis beberapa pertanyaan dalam unit-testing karena Anda seharusnya tidak dapat mengetahui struktur DB di balik aplikasi (atau mungkin berubah). Artinya, test case Anda bisa gagal karena kode Anda sendiri. Kecuali Anda menulis tes untuk tes tersebut, tetapi siapa yang akan menguji tes untuk tes ...

AxelH
sumber
-1

Pada akhirnya, tergantung pada apa yang ingin Anda uji.

Terkadang cukup untuk menguji antarmuka yang disediakan kelas Anda (mis. Rekaman dibuat dan disimpan dan dapat diambil nanti, mungkin setelah "restart"). Dalam kasus ini, boleh saja (dan biasanya merupakan ide bagus) untuk menggunakan metode yang disediakan untuk pengujian. Ini memungkinkan pengujian untuk digunakan kembali, misalnya jika Anda ingin mengubah mekanisme penyimpanan (basis data berbeda, basis data dalam-memori untuk pengujian, ...).

Perhatikan bahwa ini berarti Anda hanya benar-benar peduli bahwa kelas mematuhi kontraknya (membuat, menyimpan, dan mengambil catatan dalam kasus ini), bukan bagaimana itu mencapai ini. Jika Anda membuat tes unit Anda dengan cerdas (terhadap antarmuka, bukan kelas secara langsung), Anda dapat menguji implementasi yang berbeda, karena mereka juga harus mematuhi kontrak antarmuka.

Di sisi lain, dalam beberapa kasus Anda harus benar-benar memverifikasi bagaimana hal-hal bertahan (mungkin beberapa proses lain bergantung pada data yang berada dalam format yang benar dalam database itu?). Sekarang Anda tidak bisa hanya mengandalkan mendapatkan catatan yang benar kembali dari kelas, alih-alih Anda harus memverifikasi bahwa itu disimpan dengan benar dalam database. Dan cara paling langsung untuk melakukan itu adalah dengan menanyakan database itu sendiri.

Sekarang Anda tidak hanya peduli tentang kelas yang mematuhi kontraknya (membuat, menyimpan, dan mengambil), tetapi juga bagaimana itu mencapai ini (karena data yang bertahan perlu mematuhi antarmuka lain). Namun, sekarang tes tergantung pada antarmuka kelas dan format penyimpanan, sehingga akan sulit untuk menggunakannya kembali sepenuhnya. (Beberapa orang mungkin menyebut tes semacam ini "tes integrasi".)

hoffmale
sumber
@ downvoters: bisa Anda ceritakan alasan Anda sehingga saya dapat meningkatkan pada aspek yang Anda pikir jawaban saya kurang?
hoffmale