Pengujian unit - memulai

14

Saya baru saja memulai dengan pengujian unit tetapi saya tidak yakin apakah saya benar-benar mengerti inti dari semuanya. Saya membaca tutorial dan buku tentang itu semua, tetapi saya hanya punya dua pertanyaan cepat:

  1. Saya pikir tujuan pengujian unit adalah untuk menguji kode yang sebenarnya kami tulis. Namun, bagi saya tampaknya hanya untuk dapat menjalankan tes, kita harus mengubah kode asli, pada titik mana kita tidak benar-benar menguji kode yang kita tulis tetapi kode yang kita tulis untuk pengujian.

  2. Sebagian besar kode kami bergantung pada sumber eksternal. Namun, setelah refactoring kode kami, meskipun itu akan merusak kode asli, pengujian kami masih akan berjalan dengan baik, karena sumber eksternal hanya kotoran di dalam kasus pengujian kami. Bukankah itu mengalahkan tujuan pengujian unit?

Maaf jika saya terdengar bodoh di sini, tetapi saya pikir seseorang bisa sedikit mencerahkan saya.

Terima kasih sebelumnya.

treecoder
sumber

Jawaban:

7

$ 0,02 saya ... ini sedikit subjektif, jadi ambil dengan sebutir garam, tapi mudah-mudahan itu akan membuat Anda berpikir dan / atau memicu beberapa dialog:

  1. Tujuan utama pengujian unit kepada saya adalah untuk memastikan bahwa kode yang Anda tulis memenuhi kontrak dan kasus tepi yang dimaksudkan untuk dipenuhi oleh kode Anda. Dengan adanya unit test, Anda dapat memastikan bahwa ketika Anda (atau orang lain di masa depan) memperbaiki kode Anda, setiap konsumen eksternal kode Anda harus tetap tidak terpengaruh jika Anda memiliki cakupan negara yang tepat. (setidaknya sejauh yang Anda inginkan agar mereka tidak terpengaruh).

    Dalam sebagian besar kasus, Anda harus dapat menulis kode yang dapat dikirimkan ke produksi dan mudah diuji unit. Tempat yang baik untuk memulai mungkin untuk melihat pola dan kerangka kerja Injeksi Ketergantungan. (Atau filosofi lain untuk bahasa / platform pilihan Anda).

  2. Benar bahwa implementasi eksternal dapat memengaruhi kode Anda. Namun memastikan bahwa kode Anda berfungsi dengan benar sebagai bagian dari sistem yang lebih besar adalah fungsi pengujian integrasi . (Yang juga dapat diotomatisasi dengan berbagai tingkat usaha).

    Idealnya kode Anda hanya bergantung pada kontrak API dari komponen pihak ketiga mana pun yang berarti selama Anda mengejek memenuhi API yang benar, pengujian unit Anda tetap memberikan nilai.

    Yang mengatakan saya akan dengan mudah mengakui bahwa ada saat-saat di mana saya melakukan pengujian unit demi pengujian integrasi saja, tetapi itu hanya kasus di mana kode saya harus berinteraksi sangat banyak dengan komponen pihak ke-3 dengan API yang tidak terdokumentasi dengan baik. (Yaitu pengecualian daripada aturan).

Charlie
sumber
5
  1. Coba tulis tes Anda terlebih dahulu. Dengan begitu, Anda akan memiliki dasar yang kuat untuk perilaku kode Anda dan pengujian Anda menjadi kontrak untuk perilaku yang diperlukan dari kode Anda. Dengan demikian, mengubah kode untuk lulus tes menjadi "mengubah kode untuk memenuhi kontrak yang diusulkan oleh tes" alih-alih "mengubah kode untuk lulus tes".
  2. Nah, hati-hati tentang perbedaan antara bertopik dan mengolok-olok. Tidak terpengaruh oleh perubahan kode adalah perilaku karakteristik bertopik, tetapi tidak mengejek. Mari kita mulai dengan definisi mock:

    Objek Mock menggantikan objek nyata di bawah kondisi pengujian, dan memungkinkan memverifikasi panggilan (interaksi) terhadap dirinya sebagai bagian dari sistem atau unit test.

    -Seni Pengujian Unit

Pada dasarnya, cemoohan Anda harus memeriksa perilaku interaksi Anda yang diperlukan. Jadi, jika interaksi Anda dengan database gagal setelah refactoring, tes Anda menggunakan tiruan juga harus gagal. Ini tentu saja memiliki keterbatasan, tetapi dengan perencanaan yang cermat, ejekan Anda akan lebih dari sekadar "duduk di sana" dan itu tidak akan "mengalahkan tujuan pengujian unit".

ruhsuzbaykus
sumber
1

Mengajukan pertanyaan yang bagus sama sekali tidak bodoh.

Saya akan menjawab pertanyaan Anda.

  1. Tujuan pengujian unit bukan untuk menguji kode yang sudah Anda tulis . Ia tidak memiliki gagasan tentang waktu. Hanya di TDD Anda seharusnya melakukan pengujian terlebih dahulu, tetapi itu tidak berlaku untuk semua jenis pengujian unit. Intinya adalah untuk dapat menguji program Anda secara otomatis dan efisien di tingkat kelas. Anda melakukan apa yang perlu Anda lakukan untuk sampai ke sana, bahkan jika itu berarti mengubah kode. Dan izinkan saya memberi tahu Anda sebuah rahasia - seringkali itu artinya.
  2. Saat Anda menulis tes, Anda memiliki 2 opsi utama untuk membantu memastikan tes Anda benar:

    • Variasikan input untuk setiap tes
    • Tulis kasus uji yang memastikan program Anda berfungsi dengan baik, lalu tulis kasus uji yang sesuai yang memastikan program Anda tidak berfungsi sebagaimana mestinya.

    Ini sebuah contoh:

    TEST(MyTest, TwoPlusTwoIsFour) {
        ASSERT_EQ(4, 2+2);
    }
    
    TEST(MyTest, TwoPlusThreeIsntFour) {
        ASSERT_NE(4, 2+3);
    }
    

    Selain itu, jika Anda menguji logika di dalam kode Anda (bukan pustaka pihak ke-3), maka Anda tidak perlu khawatir tentang pemecahan kode lainnya, sementara dalam konteks itu. Anda pada dasarnya menguji cara logika Anda membungkus dan menggunakan utilitas pihak ke-3, yang merupakan skenario pengujian klasik.

Setelah Anda selesai menguji di tingkat kelas, Anda dapat melanjutkan untuk menguji integrasi antara kelas Anda (mediator, dari apa yang saya mengerti) dan perpustakaan pihak ke-3. Tes ini disebut tes integrasi, dan tidak menggunakan ejekan, melainkan implementasi konkret dari semua kelas. Mereka sedikit lebih lambat, tetapi masih sangat penting!

Yam Marcovic
sumber
1

Sepertinya Anda memiliki aplikasi monolitik yang melakukan segalanya void main(), mulai dari akses basis data hingga pembuatan keluaran. Ada beberapa langkah di sini sebelum Anda dapat memulai pengujian unit yang tepat.

1) Temukan sepotong kode yang telah ditulis / disalin lebih dari satu kali. Bahkan jika itu adil string fullName = firstName + " " + lastName. Bagi menjadi metode, seperti:

private static string GetFullName (firstName, lastName)
{
    return firstName + " " + lastName;
}

Sekarang Anda memiliki sepotong kode yang dapat diuji unit, namun sepele mungkin. Tulis tes unit untuk itu. Bilas dan ulangi proses ini. Pada akhirnya Anda akan berakhir dengan banyak metode yang dikelompokkan secara logis, dan Anda dapat mengekstraksi sejumlah kelas darinya. Sebagian besar kelas ini akan diuji.

Sebagai bonus, setelah Anda memiliki beberapa kelas diekstraksi, Anda dapat mengekstrak antarmuka dari mereka dan memperbarui program Anda untuk berbicara dengan antarmuka, bukan objek itu sendiri. Pada titik itu, Anda dapat menggunakan kerangka kerja mengejek / mematikan (atau bahkan pemintalan tangan Anda sendiri) tanpa mengubah program sama sekali. Ini sangat berguna setelah Anda mengekstraksi kueri basis data ke dalam kelas (atau banyak) karena sekarang Anda dapat memalsukan data yang harus dikembalikan oleh kueri .

Bryan Boettcher
sumber
0

Beberapa pria pintar berkata "Jika sulit untuk menguji, ini mungkin kode yang buruk". Itu sebabnya bukan hal yang buruk untuk menulis ulang kode, untuk dapat melepaskannya. Kode dengan dependensi eksternal SANGAT SULIT untuk diuji, ini merepresentasikan risc ke kode, dan harus dihindari sedapat mungkin, dan terkonsentrasi dalam area spesifik integrasi kode Anda, fx. kelas tipe fasad / gateway. Ini akan membuat perubahan pada komponen eksternal lebih mudah untuk diatasi.

Morten
sumber