Ini akan diketik secara dinamis daripada diketik secara statis. Mengetik bebek kemudian akan melakukan pekerjaan yang sama seperti antarmuka dalam bahasa yang diketik secara statis. Juga, kelas-kelasnya akan dapat dimodifikasi saat runtime sehingga kerangka kerja pengujian dapat dengan mudah mematikan atau mengolok-olok metode pada kelas yang ada. Ruby adalah salah satu bahasa seperti itu; rspec adalah kerangka uji utama untuk TDD.
Bagaimana pengujian alat bantu pengetikan dinamis
Dengan pengetikan dinamis, Anda dapat membuat objek tiruan dengan hanya membuat kelas yang memiliki antarmuka yang sama (tanda tangan metode) objek kolaborator yang Anda butuhkan untuk mengejek. Misalnya, Anda memiliki beberapa kelas yang mengirim pesan:
class MessageSender
def send
# Do something with a side effect
end
end
Katakanlah kita memiliki MessageSenderUser yang menggunakan instance MessageSender:
class MessageSenderUser
def initialize(message_sender)
@message_sender = message_sender
end
def do_stuff
...
@message_sender.send
...
@message_sender.send
...
end
end
Perhatikan penggunaan injeksi ketergantungan di sini , pokok pengujian unit. Kami akan kembali ke sana.
Anda ingin menguji bahwa MessageSenderUser#do_stuff
panggilan mengirim dua kali. Sama seperti yang Anda lakukan dalam bahasa yang diketik secara statis, Anda dapat membuat MessageSender tiruan yang menghitung berapa kali send
dipanggil. Tetapi tidak seperti bahasa yang diketik secara statis, Anda tidak perlu kelas antarmuka. Anda tinggal lanjutkan dan buat itu:
class MockMessageSender
attr_accessor :send_count
def initialize
@send_count = 0
end
def send
@send_count += 1
end
end
Dan gunakan dalam tes Anda:
mock_sender = MockMessageSender.new
MessageSenderUser.new(mock_sender).do_stuff
assert_equal(mock_sender.send_count, 2)
Dengan sendirinya, "bebek mengetik" dari bahasa yang diketik secara dinamis tidak menambah banyak pengujian dibandingkan dengan bahasa yang diketik secara statis. Tetapi bagaimana jika kelas tidak ditutup, tetapi dapat dimodifikasi saat runtime? Itu adalah pengubah game. Mari kita lihat caranya.
Bagaimana jika Anda tidak harus menggunakan injeksi ketergantungan untuk membuat kelas dapat diuji?
Misalkan MessageSenderUser hanya akan menggunakan MessageSender untuk mengirim pesan, dan Anda tidak perlu mengizinkan substitusi MessageSender dengan kelas lain. Dalam satu program sering terjadi. Mari kita menulis ulang MessageSenderUser sehingga hanya membuat dan menggunakan MessageSender, tanpa suntikan ketergantungan.
class MessageSenderUser
def initialize
@message_sender = MessageSender.new
end
def do_stuff
...
@message_sender.send
...
@message_sender.send
...
end
end
MessageSenderUser sekarang lebih mudah digunakan: Tidak ada yang membuatnya perlu membuat MessageSender agar dapat digunakan. Ini tidak terlihat seperti peningkatan besar dalam contoh sederhana ini, tetapi sekarang bayangkan bahwa MessageSenderUser dibuat di lebih dari satu tempat, atau memiliki tiga dependensi. Sekarang sistem memiliki banyak sekali contoh yang melintas hanya untuk membuat unit test senang, bukan karena itu perlu meningkatkan desain sama sekali.
Kelas terbuka memungkinkan Anda menguji tanpa injeksi ketergantungan
Kerangka uji dalam bahasa dengan pengetikan dinamis dan kelas terbuka dapat membuat TDD cukup bagus. Berikut cuplikan kode dari tes rspec untuk MessageSenderUser:
mock_message_sender = mock MessageSender
MessageSender.should_receive(:new).and_return(mock_message_sender)
mock_message_sender.should_receive(:send).twice.with(no_arguments)
MessageSenderUser.new.do_stuff
Itu seluruh tes. Jika MessageSenderUser#do_stuff
tidak memanggil MessageSender#send
tepat dua kali, tes ini gagal. Kelas MessageSender yang sebenarnya tidak pernah dipanggil: Kami memberi tahu tes bahwa setiap kali seseorang mencoba membuat MessageSender, mereka seharusnya mendapatkan MessageSender tiruan kita sebagai gantinya. Tidak diperlukan injeksi ketergantungan.
Sangat menyenangkan untuk melakukan begitu banyak tes sederhana. Lebih baik tidak harus menggunakan injeksi ketergantungan kecuali jika itu benar-benar masuk akal untuk desain Anda.
Tapi apa hubungannya ini dengan kelas terbuka? Perhatikan panggilan ke MessageSender.should_receive
. Kami tidak mendefinisikan #should_receive ketika kami menulis MessageSender, jadi siapa yang melakukannya? Jawabannya adalah bahwa kerangka kerja pengujian, membuat beberapa modifikasi hati-hati dari kelas sistem, dapat membuatnya muncul karena melalui #should_receive didefinisikan pada setiap objek. Jika Anda berpikir bahwa memodifikasi kelas sistem seperti itu membutuhkan perhatian, Anda benar. Tetapi ini adalah hal yang sempurna untuk apa yang dilakukan oleh perpustakaan tes di sini, dan kelas terbuka memungkinkannya.