Bagaimana cara kerja pengujian unit?


23

Saya mencoba membuat kode saya lebih kuat dan saya telah membaca tentang pengujian unit, tetapi saya merasa sangat sulit untuk menemukan penggunaan yang sebenarnya berguna. Misalnya, contoh Wikipedia :

public class TestAdder {
    public void testSum() {
        Adder adder = new AdderImpl();
        assert(adder.add(1, 1) == 2);
        assert(adder.add(1, 2) == 3);
        assert(adder.add(2, 2) == 4);
        assert(adder.add(0, 0) == 0);
        assert(adder.add(-1, -2) == -3);
        assert(adder.add(-1, 1) == 0);
        assert(adder.add(1234, 988) == 2222);
    }
}

Saya merasa bahwa tes ini sama sekali tidak berguna, karena Anda diharuskan menghitung secara manual hasil yang diinginkan dan mengujinya, saya merasa seperti unit test yang lebih baik di sini adalah

assert(adder.add(a, b) == (a+b));

tapi kemudian ini hanya mengkode fungsi itu sendiri dalam ujian. Dapatkah seseorang memberi saya contoh di mana pengujian unit sebenarnya berguna? FYI Saya saat ini mengkode sebagian besar fungsi "prosedural" yang mengambil ~ 10 boolean dan beberapa int dan memberi saya hasil int berdasarkan ini, saya merasa seperti satu-satunya pengujian unit yang bisa saya lakukan adalah dengan hanya mengkode ulang algoritma dalam uji. sunting: Saya juga seharusnya telah memprioritaskan ini saat porting (mungkin dirancang dengan buruk) kode ruby ​​(yang saya tidak buat)


14
How does unit testing work?Tidak ada satu yang benar-benar tahu :)
yannis

30
"Anda diharuskan menghitung secara manual hasil yang diinginkan". Bagaimana itu "sama sekali tidak berguna"? Bagaimana lagi Anda bisa yakin jawabannya benar?
S.Lott

9
@ S.Lott: Ini disebut kemajuan, pada zaman dahulu orang menggunakan komputer untuk menghitung angka dan menghemat waktu, di zaman modern ini orang menghabiskan waktu untuk memastikan komputer dapat menghitung angka: D
Coder

2
@Coder: tujuan pengujian unit bukan "untuk menghitung angka dan menghemat waktu";)
Andres F.

7
@lezebulon: contoh dari Wikipedia tidak terlalu bagus, tapi itu adalah masalah dengan test case khusus itu, tidak dengan pengujian unit secara umum. Sekitar setengah dari data uji dari contoh tidak menambahkan sesuatu yang baru, membuatnya menjadi berlebihan (saya takut untuk memikirkan apa yang akan dilakukan oleh penulis tes itu dengan skenario yang lebih kompleks). Tes yang lebih bermakna akan mempartisi data uji setidaknya dalam skenario berikut: "dapatkah itu menambah angka negatif?", "Apakah nol netral?", "Dapatkah menambahkan angka negatif dan positif?".
Andres F.

Jawaban:


26

Tes unit, jika Anda menguji unit yang cukup kecil, selalu menyatakan yang sangat jelas.

Alasan bahwa add(x, y)bahkan mendapat menyebutkan unit test, adalah karena suatu saat nanti seseorang akan masuk ke adddan memasukkan kode penanganan logika pajak khusus tidak menyadari bahwa add digunakan di mana-mana.

Tes unit sangat banyak tentang prinsip asosiatif: jika A melakukan B, dan B melakukan C, maka A melakukan C. "A melakukan C" adalah tes tingkat yang lebih tinggi. Misalnya, pertimbangkan kode bisnis berikut yang sepenuhnya sah:

public void LoginUser (string username, string password) {
    var user = db.FetchUser (username);

    if (user.Password != password)
        throw new Exception ("invalid password");

    var roles = db.FetchRoles (user);

    if (! roles.Contains ("member"))
        throw new Exception ("not a member");

    Session["user"] = user;
}

Sepintas ini terlihat seperti metode yang luar biasa untuk pengujian unit, karena memiliki tujuan yang sangat jelas. Namun, ia melakukan sekitar 5 hal berbeda. Setiap hal memiliki kasus yang valid dan tidak valid, dan akan membuat permutasi yang sangat besar dari unit test. Idealnya ini dirinci lebih lanjut:

public void LoginUser (string username, string password) {

    var user = _userRepo.FetchValidUser (username, password);

    _rolesRepo.CheckUserForRole (user, "member");

    _localStorage.StoreValue ("user", user);
}

Sekarang kita ke unit. Satu unit tes tidak peduli untuk apa _userRepoperilaku yang dianggap valid FetchValidUser, hanya itu yang disebut. Anda dapat menggunakan tes lain untuk memastikan apa yang dimaksud dengan pengguna yang valid. Demikian pula untuk CheckUserForRole... Anda telah memisahkan tes Anda dari mengetahui seperti apa struktur Peran itu. Anda juga telah memisahkan seluruh program agar tidak diikat dengan ketat Session. Saya membayangkan semua bagian yang hilang di sini akan terlihat seperti:

class UserRepository : IUserRepository
{
    public User FetchValidUser (string username, string password)
    {
        var user = db.FetchUser (username);

        if (user.Password != password)
            throw new Exception ("invalid password");

        return user;
    }
}

class RoleRepository : IRoleRepository
{
    public void CheckUserForRole (User user, string role)
    {
        var roles = db.FetchRoles (user);

        if (! roles.Contains (role))
            throw new Exception ("not a member");
    }
}

class SessionStorage : ILocalStorage
{
    public void StoreValue (string key, object value)
    {
        Session[key] = value;
    }
}

Dengan refactoring Anda telah menyelesaikan beberapa hal sekaligus. Program ini jauh lebih mendukung untuk merobohkan struktur yang mendasarinya (Anda dapat membuang lapisan basis data untuk NoSQL), atau menambahkan penguncian dengan mulus begitu Anda sadar bahwa Sessiontidak ada thread-safe atau apa pun. Anda juga sekarang telah memberikan diri Anda tes yang sangat sederhana untuk menulis untuk tiga dependensi ini.

Semoga ini membantu :)


13

Saat ini saya sedang mengkode sebagian besar fungsi "prosedural" yang mengambil ~ 10 boolean dan beberapa int dan memberikan saya hasil int berdasarkan ini, saya merasa seperti satu-satunya pengujian unit yang bisa saya lakukan adalah dengan hanya mengkode ulang algoritma dalam pengujian

Saya cukup yakin bahwa masing-masing fungsi prosedural Anda bersifat deterministik, sehingga mengembalikan hasil khusus untuk setiap rangkaian nilai input yang diberikan. Idealnya, Anda akan memiliki spesifikasi fungsional dari mana Anda dapat mengetahui hasil apa yang harus Anda terima untuk set nilai input tertentu. Dalam kekurangan itu, Anda dapat menjalankan kode ruby ​​(yang dianggap berfungsi dengan benar) untuk set nilai input tertentu, dan merekam hasilnya. Kemudian, Anda perlu KERAS KODE hasil tes Anda. Tes ini seharusnya menjadi bukti bahwa kode Anda memang menghasilkan hasil yang diketahui benar .


+1 untuk menjalankan kode yang ada dan merekam hasilnya. Dalam situasi ini, itu mungkin pendekatan pragmatis.
MarkJ

12

Karena tampaknya tidak ada orang lain yang memberikan contoh nyata:

    public void testRoman() {
        RomanNumeral numeral = new RomanNumeral();
        assert( numeral.toRoman(1) == "I" )
        assert( numeral.toRoman(4) == "IV" )
        assert( numeral.toRoman(5) == "V" )
        assert( numeral.toRoman(9) == "IX" )
        assert( numeral.toRoman(10) == "X" )
    }
    public void testSqrt() {
        assert( sqrt(4) == 2 )
        assert( sqrt(9) == 3 )
    }

Kamu bilang:

Saya merasa bahwa tes ini sama sekali tidak berguna, karena Anda diharuskan menghitung secara manual hasil yang diinginkan dan mengujinya

Tetapi intinya adalah bahwa Anda jauh lebih kecil kemungkinannya untuk membuat kesalahan (atau paling tidak lebih mungkin untuk melihat kesalahan Anda) ketika melakukan perhitungan manual kemudian ketika coding.

Seberapa besar kemungkinan Anda membuat kesalahan dalam kode konversi desimal ke roman Anda? Sangat mungkin. Seberapa besar kemungkinan Anda membuat kesalahan ketika mengonversi angka desimal ke angka romawi dengan tangan? Sangat tidak mungkin. Itu sebabnya kami menguji terhadap perhitungan manual.

Seberapa besar kemungkinan Anda membuat kesalahan ketika menerapkan fungsi root kuadrat? Sangat mungkin. Seberapa besar kemungkinan Anda melakukan kesalahan saat menghitung akar kuadrat dengan tangan? Mungkin lebih mungkin. Tetapi dengan sqrt, Anda dapat menggunakan kalkulator untuk mendapatkan jawabannya.

FYI Saya saat ini mengkode sebagian besar fungsi "prosedural" yang mengambil ~ 10 boolean dan beberapa int dan memberi saya hasil int berdasarkan ini, saya merasa seperti satu-satunya pengujian unit yang bisa saya lakukan adalah dengan hanya mengkode ulang algoritma dalam uji

Jadi saya akan berspekulasi tentang apa yang terjadi di sini. Fungsi Anda agak rumit, jadi sulit untuk mengetahui dari input apa output seharusnya. Untuk melakukan itu, Anda harus secara manual menjalankan (di kepala Anda) fungsi untuk mencari tahu apa outputnya. Maklum, itu sepertinya tidak berguna dan rawan kesalahan.

Kuncinya adalah Anda ingin menemukan output yang benar. Tetapi Anda harus menguji output tersebut terhadap sesuatu yang diketahui benar. Ini tidak baik untuk menulis algoritma Anda sendiri untuk menghitung itu karena itu mungkin sangat tidak benar. Dalam hal ini terlalu sulit untuk menghitung nilai secara manual.

Saya akan kembali ke kode ruby, dan menjalankan fungsi asli ini dengan berbagai parameter. Saya akan mengambil hasil dari kode ruby ​​dan memasukkannya ke dalam unit test. Dengan begitu Anda tidak perlu melakukan perhitungan manual. Tetapi Anda menguji terhadap kode asli. Itu seharusnya membantu menjaga hasil yang sama, tetapi jika ada bug di aslinya maka itu tidak akan membantu Anda. Pada dasarnya, Anda dapat memperlakukan kode asli seperti kalkulator pada contoh sqrt.

Jika Anda menunjukkan kode aktual yang Anda porting, kami dapat memberikan umpan balik yang lebih rinci tentang cara mendekati masalah.


Dan jika kode Ruby memang memiliki bug yang Anda tidak tahu tentang itu tidak ada dalam kode baru Anda dan kode Anda gagal tes unit berdasarkan pada output Ruby, maka penyelidikan mengapa gagal itu pada akhirnya akan membenarkan Anda dan menghasilkan bug Ruby laten ditemukan. Jadi itu keren sekali.
Adam Wuerl

11

Saya merasa seperti satu-satunya pengujian unit yang bisa saya lakukan adalah dengan hanya kode ulang algoritma dalam pengujian

Anda hampir benar untuk kelas yang begitu sederhana.

Cobalah untuk kalkulator yang lebih kompleks .. Seperti kalkulator skor bowling.

Nilai unit test lebih mudah dilihat ketika Anda memiliki aturan "bisnis" yang lebih kompleks dengan skenario berbeda untuk diuji.

Saya tidak mengatakan Anda tidak boleh menguji coba kalkulator pabrik (Apakah akun kalkulator Anda mengeluarkan nilai seperti 1/3 yang tidak dapat diwakili? Apa hubungannya dengan pembagian dengan nol?) Tetapi Anda akan melihat nilai lebih jelas jika Anda menguji sesuatu dengan lebih banyak cabang untuk mendapatkan cakupan.


4
+1 untuk mencatatnya menjadi lebih berguna untuk fungsi yang rumit. Bagaimana jika Anda memutuskan untuk memperluas adder.add () ke nilai floating point? Matriks? Nilai akun leger?
joshin4colours

6

Meskipun fanatik agama sekitar 100% cakupan kode, saya akan mengatakan bahwa tidak setiap metode harus diuji unit. Hanya fungsionalitas yang berisi logika bisnis yang bermakna. Fungsi yang hanya menambahkan angka tidak ada gunanya untuk diuji.

Saat ini saya sedang mengkode sebagian besar fungsi "prosedural" yang mengambil ~ 10 boolean dan beberapa int dan memberi saya hasil int berdasarkan ini

Ada masalah Anda yang sebenarnya di sana. Jika pengujian unit tampaknya sulit atau sia-sia maka kemungkinan karena cacat desain. Jika lebih berorientasi objek tanda tangan metode Anda tidak akan begitu besar dan akan ada lebih sedikit input yang mungkin untuk diuji.

Saya tidak perlu masuk ke OO saya lebih unggul dari pemrograman prosedural ...


dalam hal ini "tanda tangan" dari metode ini tidak besar, saya baru saja membaca dari std :: vector <bool> yang merupakan anggota kelas. Saya juga seharusnya sudah tahu bahwa saya porting (mungkin dirancang dengan buruk) kode ruby ​​(yang saya tidak buat)
lezebulon

2
@lezebulon Terlepas dari apakah ada banyak kemungkinan input untuk metode tunggal untuk menerima maka metode itu melakukan terlalu banyak .
maple_shaft

3

Dalam pandangan saya, tes unit bahkan berguna di kelas adder kecil Anda: jangan berpikir tentang "pengodean ulang" algoritma dan menganggapnya sebagai kotak hitam dengan satu-satunya pengetahuan yang Anda miliki tentang perilaku fungsional (jika Anda terbiasa dengan multiplikasi cepat, Anda tahu beberapa upaya yang lebih cepat, tetapi lebih rumit daripada menggunakan "a * b") dan antarmuka publik Anda. Daripada Anda harus bertanya pada diri sendiri, "Apa yang salah?" ...

Dalam kebanyakan kasus, ini terjadi di perbatasan (saya melihat Anda menguji sudah menambahkan pola ini ++, -, + -, 00 - waktu untuk menyelesaikannya dengan - +, 0+, 0, 0, +0, -0). Pikirkan apa yang terjadi pada MAX_INT dan MIN_INT saat menambahkan atau mengurangi (menambahkan negatif;)) di sana. Atau coba pastikan tes Anda terlihat persis seperti apa yang terjadi pada dan sekitar nol.

Secara keseluruhan rahasianya sangat sederhana (mungkin untuk yang lebih rumit juga;)) untuk kelas sederhana: pikirkan kontrak kelas Anda (lihat desain dengan kontrak) dan kemudian uji terhadap mereka. Semakin baik Anda mengetahui inv, pre dan post Anda, "pelengkap" tes Anda akan.

Petunjuk untuk kelas tes Anda: cobalah untuk menulis hanya satu pernyataan dalam suatu metode. Berikan nama metode yang baik (mis. "TestAddingToMaxInt", "testAddingTwoNegatives") untuk mendapatkan umpan balik terbaik ketika pengujian Anda gagal setelah perubahan kode.


2

Daripada menguji untuk nilai pengembalian yang dihitung secara manual, atau menduplikasi logika dalam pengujian untuk menghitung nilai pengembalian yang diharapkan, uji nilai pengembalian untuk properti yang diharapkan.

Misalnya, jika Anda ingin menguji metode yang membalikkan matriks, Anda tidak ingin membalikkan nilai input Anda secara manual, Anda harus mengalikan nilai pengembalian dengan input dan memeriksa apakah Anda mendapatkan matriks identitas.

Untuk menerapkan pendekatan ini pada metode Anda, Anda harus mempertimbangkan tujuan dan semantiknya, untuk mengidentifikasi properti apa yang akan memiliki nilai pengembalian relatif terhadap input.


2

Tes unit adalah alat produktivitas. Anda menerima permintaan perubahan, mengimplementasikannya, lalu menjalankan kode Anda melalui unit test gambit. Pengujian otomatis ini menghemat waktu.

I feel that this test is totally useless, because you are required to manually compute the wanted result and test it, I feel like a better unit test here would be

Titik diperdebatkan. Tes dalam contoh hanya menunjukkan bagaimana membuat instance kelas dan menjalankannya melalui serangkaian tes. Berkonsentrasi pada hal-hal kecil dalam satu implementasi tidak ada hutan untuk pepohonan.

Can someone provide me with an example where unit testing is actually useful?

Anda memiliki entitas Karyawan. Entitas mengandung nama dan alamat. Klien memutuskan untuk menambahkan bidang ReportsTo.

void TestBusinessLayer()
{
   int employeeID = 1234
   Employee employee = Employee.GetEmployee(employeeID)
   BusinessLayer bl = new BusinessLayer()
   Assert.isTrue(bl.Add(employee))//assume Add returns true on pass
}

Itu adalah tes dasar BL untuk bekerja dengan seorang karyawan. Kode akan lulus / gagal perubahan skema yang baru saja Anda buat. Ingatlah bahwa pernyataan bukan satu-satunya hal yang dilakukan tes. Menjalankan kode juga memastikan tidak ada pengecualian yang menggelembung.

Seiring waktu, memiliki tes di tempat membuatnya lebih mudah untuk membuat perubahan secara umum. Kode secara otomatis diuji untuk pengecualian dan terhadap Asersi yang Anda buat. Ini menghindari banyak overhead yang dikeluarkan oleh pengujian manual oleh grup QA. Sementara UI masih cukup sulit untuk diotomatisasi, lapisan lain umumnya sangat mudah dengan asumsi Anda menggunakan pengubah akses dengan benar.

I feel like the only unit testing I could do would be to simply re-code the algorithm in the test.

Bahkan logika prosedural mudah dirangkum dalam suatu fungsi. Enkapsulasi, instantiate, dan masukkan int / primitif untuk diuji (atau objek tiruan). Jangan salin tempel kode ke Tes Unit. Itu mengalahkan KERING. Itu juga mengalahkan tes sepenuhnya karena Anda tidak menguji kode, tetapi salinan kode. Jika kode yang seharusnya diuji mengalami perubahan, tes tetap berlalu!


<pedantry> "gamut", bukan "gambit". </
pedantry

@ chao lol belajar sesuatu yang baru setiap hari.
P.Brian.Mackey

2

Mengambil contoh Anda (dengan sedikit refactoring),

assert(a + b, math.add(a, b));

tidak membantu untuk:

  • memahami bagaimana math.addberperilaku secara internal,
  • tahu apa yang akan terjadi dengan kasus tepi.

Ini seperti mengatakan:

  • Jika Anda ingin tahu apa metode ini, buka dan lihat sendiri ratusan baris kode sumber (karena, ya, math.add dapat berisi ratusan LOC; lihat di bawah).
  • Saya tidak ingin tahu apakah metode ini bekerja dengan benar. Tidak apa-apa jika nilai yang diharapkan dan aktual berbeda dari apa yang saya harapkan .

Ini juga berarti Anda tidak perlu menambahkan tes seperti:

assert(3, math.add(1, 2));
assert(4, math.add(2, 2));

Mereka tidak membantu, atau setidaknya, begitu Anda membuat pernyataan pertama, yang kedua tidak membawa apa-apa yang berguna.

Sebaliknya, bagaimana dengan:

const numeric Pi = 3.1415926535897932384626433832795;
const numeric Expected = 4.1415926535897932384626433832795;
assert(Expected, math.add(Pi, 1),
    "Adding an integer to a long numeric doesn't give a long numeric result.");
assert(Expected, math.add(1, Pi),
    "Adding a long numeric to an integer doesn't give a long numeric result.");

Ini cukup jelas dan sangat membantu bagi Anda dan orang yang akan menjaga kode sumber nanti. Bayangkan orang ini melakukan sedikit modifikasi pada math.adduntuk menyederhanakan kode dan mengoptimalkan kinerja, dan melihat hasil tes seperti:

Test TestNumeric() failed on assertion 2, line 5: Adding a long numeric to an
integer doesn't give a long numeric result.

Expected value: 4.1415926535897932384626433832795
Actual value: 4

orang ini akan segera memahami bahwa metode yang baru dimodifikasi tergantung pada urutan argumen: jika argumen pertama adalah bilangan bulat dan yang kedua adalah angka yang panjang, hasilnya akan berupa bilangan bulat, sedangkan angka yang panjang diharapkan.

Dengan cara yang sama, memperoleh nilai aktual 4.141592pada pernyataan pertama cukup jelas: Anda tahu bahwa metode ini diharapkan dapat menangani presisi besar , tetapi sebenarnya gagal.

Untuk alasan yang sama, dua pernyataan berikut dapat masuk akal dalam beberapa bahasa:

// We don't expect a concatenation. `math` library is not intended for this.
assert(0, math.add("Hello", "World"));

// We expect the method to convert every string as if it was a decimal.
assert(5, math.add("0x2F", 5));

Juga, bagaimana dengan:

assert(numeric.Infinity, math.add(numeric.Infinity, 1));

Cukup jelas juga: Anda ingin metode Anda dapat menangani infinity dengan benar. Melampaui batas tanpa batas atau melempar pengecualian bukanlah perilaku yang diharapkan.

Atau mungkin, tergantung pada bahasa Anda, ini akan lebih masuk akal?

/**
 * Ensures that when adding numbers which exceed the maximum value, the method
 * fails with OverflowException, instead of restarting at numeric.Minimum + 1.
 */
TestOverflow()
{
    UnitTest.ExpectException(ofType(OverflowException));

    numeric result = math.add(numeric.Maximum, 1));

    UnitTest.Fail("The tested code succeeded, while an OverflowException was
        expected.");
}

1

Untuk fungsi yang sangat sederhana seperti menambahkan, pengujian dapat dianggap tidak perlu, tetapi karena fungsi Anda menjadi lebih kompleks, itu menjadi semakin jelas mengapa pengujian diperlukan.

Pikirkan tentang apa yang Anda lakukan ketika Anda pemrograman (tanpa pengujian unit). Biasanya Anda menulis beberapa kode, menjalankannya, melihat bahwa itu berfungsi, dan beralih ke hal berikutnya, bukan? Ketika Anda menulis lebih banyak kode, terutama di sistem / GUI / situs web yang sangat besar, Anda merasa harus melakukan lebih banyak lagi "menjalankan dan melihat apakah itu berfungsi". Anda harus mencoba ini dan mencobanya. Kemudian, Anda membuat beberapa perubahan dan Anda harus mencoba hal-hal yang sama lagi. Menjadi sangat jelas bahwa Anda dapat menghemat waktu dengan menulis unit test yang akan mengotomatiskan seluruh bagian "berlari dan melihat apakah itu berfungsi".

Ketika proyek Anda menjadi semakin besar, semakin banyak hal yang harus Anda "jalankan dan lihat apakah itu berhasil" untuk menjadi tidak realistis. Jadi Anda akhirnya hanya menjalankan dan mencoba beberapa komponen utama dari GUI / proyek dan kemudian berharap semuanya baik-baik saja. Ini adalah resep untuk bencana. Tentu saja Anda, sebagai manusia, tidak dapat berulang kali menguji untuk setiap situasi yang mungkin digunakan klien Anda jika GUI digunakan oleh ratusan orang. Jika Anda memiliki tes unit di tempat, Anda bisa menjalankan tes sebelum mengirimkan versi stabil, atau bahkan sebelum melakukan ke repositori pusat (jika tempat kerja Anda menggunakannya). Dan, jika ada bug yang ditemukan di lain waktu, Anda bisa menambahkan unit test untuk memeriksanya di masa mendatang.


1

Salah satu manfaat dari penulisan unit test adalah membantu Anda menulis kode yang lebih kuat dengan memaksa Anda untuk berpikir tentang kasus tepi. Bagaimana dengan pengujian untuk beberapa kasus tepi, seperti integer overflow, pemotongan desimal, atau penanganan nulls untuk parameter?


0

Mungkin Anda menganggap add () diimplementasikan dengan instruksi ADD. Jika beberapa programmer junior atau insinyur perangkat keras mengimplementasikan kembali fungsi add () menggunakan ANDS / ORS / XORS, bit invert dan shift, Anda mungkin ingin mengujinya berdasarkan instruksi ADD.

Secara umum, jika Anda mengganti nyali add (), atau unit yang sedang diuji, dengan nomor acak atau generator keluaran, bagaimana Anda tahu bahwa ada sesuatu yang rusak? Encode pengetahuan itu dalam unit test Anda. Jika tidak ada yang tahu apakah itu rusak, maka cukup periksa beberapa kode untuk rand () dan pulanglah, pekerjaan Anda selesai.


0

Saya mungkin telah melewatkannya di antara semua balasan tetapi, bagi saya, penggerak utama di balik Unit Testing lebih sedikit tentang membuktikan kebenaran suatu metode hari ini tetapi itu membuktikan kelanjutan yang benar dari metode tersebut ketika Anda pernah mengubahnya .

Ambil fungsi sederhana, seperti mengembalikan jumlah item dalam beberapa koleksi. Hari ini, ketika daftar Anda didasarkan pada satu struktur data internal yang Anda ketahui dengan baik, Anda mungkin berpikir bahwa metode ini sangat jelas menyakitkan sehingga Anda tidak memerlukan tes untuk itu. Kemudian, dalam beberapa bulan atau tahun, Anda (atau orang lain ) memutuskan untuk mengganti struktur daftar internal. Anda masih perlu tahu bahwa getCount () mengembalikan nilai yang benar.

Di situlah Tes Unit Anda benar-benar menjadi milik mereka.

Anda dapat mengubah implementasi internal kode Anda tetapi untuk konsumen kode itu, hasilnya tetap sama.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.