Bagaimana cara menerapkan TDD untuk fungsi baca / tulis?

10

Sepertinya masalah ayam dan telur.

Anda dapat membuat fungsi tulis menulis ke beberapa penyimpanan data, tetapi tidak pernah tahu Anda menyimpannya dengan benar tanpa fungsi baca yang teruji.

Anda dapat membuat fungsi baca dibaca dari penyimpanan data, tetapi bagaimana Anda meletakkan barang-barang di penyimpanan data itu, untuk dibaca, tanpa fungsi tulis yang teruji?

EDIT:

Saya terhubung ke dan melakukan transaksi dengan database SQL untuk menyimpan dan memuat objek untuk digunakan. Tidak ada gunanya menguji fungsi akses yang disediakan DB, tapi saya membungkus fungsi DB tersebut untuk membuat serial / deserialize objek. Saya ingin memastikan saya menulis dan membaca hal yang benar ke dan dari DB dengan benar.

Ini tidak seperti menambah / menghapus, seperti @snowman menyebutkan. Saya ingin tahu bahwa konten yang saya tulis sudah benar, tetapi itu membutuhkan fungsi baca yang teruji. Ketika saya membaca, saya ingin memastikan bahwa bacaan saya telah dengan benar menciptakan objek yang setara dengan apa yang ditulis; tapi itu membutuhkan fungsi tulis yang sudah teruji.

pengguna2738698
sumber
Apakah Anda menulis penyimpanan data Anda sendiri, atau menggunakan yang sudah ada? Jika Anda menggunakan yang sudah ada, anggap sudah berfungsi. Jika Anda menulis sendiri, ini berfungsi dengan cara yang sama seperti menulis perangkat lunak lain menggunakan TDD.
Robert Harvey
1
Meskipun terkait erat, saya tidak berpikir ini adalah duplikat dari pertanyaan khusus itu. Target dupe berbicara tentang menambah / menghapus, yang ini baca / tulis. Perbedaannya adalah ketergantungan baca / tulis yang cenderung bergantung pada isi objek yang sedang dibaca / ditulis, sedangkan tes tambah / hapus sederhana mungkin akan jauh lebih sederhana: apakah objek itu ada atau tidak.
2
Anda bisa membuat basis data dengan data dan tidak ada fungsi tulis sama sekali untuk menguji fungsi baca.
JeffO

Jawaban:

7

Mulai dengan Fungsi Baca.

  • Dalam pengaturan pengujian : buat database dan tambahkan data pengujian. baik melalui skrip migrasi atau dari cadangan. Karena ini bukan kode Anda, itu tidak memerlukan tes dalam TDD

  • Dalam pengujian : instanciate repositori Anda, arahkan ke pada db tes Anda dan panggil metode Baca. Periksa apakah data uji dikembalikan.

Sekarang Anda memiliki fungsi baca yang teruji sepenuhnya, Anda dapat pindah ke fungsi Tulis, yang dapat menggunakan Baca yang ada untuk memverifikasi hasilnya sendiri

Ewan
sumber
Saya kira Anda bisa membuat DB di memori untuk mempercepat, tapi itu mungkin terlalu rumit. Mengapa tidak menggunakan tiruan sebagai gantinya dalam unit test?
BЈовић
1
Sedikit Advokat Iblis di sini, tetapi bagaimana Anda menguji bahwa database dibuat dengan benar? Seperti yang dinyatakan OP, ayam dan telur.
user949300
1
@ Ewan - Saya sangat setuju bahwa Anda tidak boleh menguji kode DB mereka. Tetapi bagaimana Anda tahu bahwa kode penyiapan DB Anda tidak melupakan INSERT di suatu tempat atau memasukkan nilai yang salah dalam kolom?
user949300
1
dari pendekatan TDD murni tes ADALAH persyaratan. jadi secara logis tidak bisa salah. obvs di dunia nyata Anda harus mengamatinya
Ewan
1
Quis custodiet ipsos custodes? Atau, "Siapa yang menguji tes?" :-) Saya setuju dengan Anda bahwa di dunia TDD purist ini akan menjadi sangat membosankan dan rawan bug (khususnya jika itu adalah struktur tabel ganda yang rumit dengan 8 GABUNG) cara untuk melakukannya. Terpilih.
user949300
6

Saya sering hanya menulis dan diikuti dengan membaca. mis. (kodesemu)

Foo foo1 = setup some object to write
File tempfile = create a tempfile, possibly in memory 
writeFoo(foo1, tempfile) 
Foo foo2 = readFoo(tempfile) 
assertEquals(foo1, foo2); 
clean-up goes here

Ditambahkan nanti

Selain solusi ini menjadi "prgamatic" dan "cukup baik", orang dapat berpendapat bahwa solusi lain menguji hal yang salah . Menguji apakah string atau pernyataan SQL cocok bukan ide yang buruk, saya sudah melakukannya sendiri, tetapi sedang menguji efek samping, dan rapuh. Bagaimana jika Anda mengubah kapitalisasi, menambah bidang, atau memperbarui nomor versi dalam data Anda? Bagaimana jika driver SQL Anda mengubah urutan panggilan untuk efisiensi, atau serializer XML Anda yang diperbarui menambah ruang ekstra atau mengubah versi skema?

Sekarang, jika Anda harus sangat ketat mematuhi beberapa spesifikasi resmi, maka saya setuju bahwa memeriksa detail yang baik adalah tepat.

pengguna949300
sumber
1
Karena 90% pseudocode yang sangat padat? Tidak yakin. Mungkin menyorot teks dan membuat kode kurang berisik?
RubberDuck
1
Ya @ Ewan. Orang fanatik akan tidak menyukai hal ini, tetapi programmer pragmatis akan mengatakan "cukup baik" dan melanjutkan.
RubberDuck
1
saya agak membaca pertanyaan sebagai .. "dengan asumsi saya mengikuti TDD seperti seorang fanatik ..."
Ewan
1
interpretasi saya terhadap OP dan TDD adalah bahwa tes Anda harus ditulis terlebih dahulu dan tidak menggunakan keduanya baca dan tulis kecuali ada yang diuji di tempat lain juga.
Ewan
2
Anda menguji, 'baca harus mengembalikan apa yang saya tulis' tetapi persyaratannya adalah 'baca harus mengembalikan data dari db' dan 'tulis harus menulis data ke db'
Ewan
4

Jangan. Jangan uji unit I / O. Membuang buang waktu saja.

Logika uji unit. Jika ada banyak logika yang ingin Anda uji dalam kode I / O, Anda harus refactor kode Anda untuk memisahkan logika bagaimana Anda I / O dan apa yang saya / O Anda lakukan dari bisnis yang sebenarnya melakukan I / O (yang hampir mustahil untuk diuji).

Untuk sedikit menguraikan, jika Anda ingin menguji server HTTP, Anda harus melakukannya melalui dua jenis tes: tes integrasi dan tes unit. Tes unit tidak boleh berinteraksi dengan I / O sama sekali. Itu lambat dan memperkenalkan banyak kondisi kesalahan yang tidak ada hubungannya dengan kebenaran kode Anda. Tes unit seharusnya tidak tergantung pada kondisi jaringan Anda!

Kode Anda harus terpisah:

  • Logika menentukan informasi apa yang akan dikirim
  • Logika menentukan byte mana yang akan dikirim untuk mengirim sedikit informasi tertentu (bagaimana cara menyandikan respons, dll. Ke dalam byte mentah), dan
  • Mekanisme penulisan byte-byte tersebut ke soket.

Dua yang pertama melibatkan logika dan keputusan dan membutuhkan tes unit. Yang terakhir tidak melibatkan pengambilan banyak jika ada keputusan dan dapat diuji dengan luar biasa menggunakan pengujian integrasi.

Sebenarnya ini hanya desain yang bagus, tetapi salah satu alasannya adalah membuatnya lebih mudah untuk diuji.


Berikut ini beberapa contohnya:

  • Jika Anda menulis kode yang mendapatkan data dari basis data relasional, Anda dapat menguji bagaimana Anda memetakan data yang dikembalikan dari kueri relasional ke model aplikasi Anda.
  • Jika Anda menulis kode yang menulis data ke database relasional, Anda dapat menguji unit mana dari data yang ingin Anda tulis ke database tanpa benar-benar menguji permintaan SQL tertentu yang Anda gunakan. Misalnya, Anda mungkin menyimpan dua salinan status aplikasi Anda dalam memori: salinan yang mewakili seperti apa database dan copy pekerjaan. Saat Anda ingin menyinkronkan ke basis data, Anda perlu membuatnya berbeda dan menulis perbedaannya ke basis data. Anda dapat dengan mudah menguji unit kode diff itu.
  • Jika Anda menulis kode yang membaca sesuatu dari file konfigurasi, Anda ingin menguji parser format file konfigurasi Anda, tetapi dengan string dari file sumber tes Anda daripada string yang Anda dapatkan dari disk.
Miles Rout
sumber
2

Saya tidak tahu apakah ini praktik standar atau tidak, tetapi itu berfungsi dengan baik untuk saya.

Dalam implementasi metode baca tulis non-database saya menggunakan tipe-spesifik saya sendiri toString() dan fromString()metode sebagai detail implementasi.

Ini dapat dengan mudah diuji secara terpisah:

 assertEquals("<xml><car type='porsche'>....", new Car("porsche").toString());

Untuk metode baca tulis yang sebenarnya saya punya satu tes integrasi yang secara fisik membaca dan menulis dalam satu tes

Ngomong-ngomong: Apakah ada yang salah dengan satu tes yang tes baca / tulis bersama?

k3b
sumber
Mungkin rasanya tidak enak atau "murni", tetapi ini adalah solusi pragmatis.
RubberDuck
Saya juga menyukai ide pengujian baca & tulis bersama. ToString () Anda adalah kompromi pragmatis yang bagus.
user949300
1

Data yang diketahui harus diformat dengan cara yang diketahui. Cara termudah untuk mengimplementasikan ini adalah dengan menggunakan string konstan dan membandingkan hasilnya, seperti yang dijelaskan oleh @ k3b.

Anda tidak terbatas pada konstanta. Mungkin ada sejumlah properti dari data tertulis yang dapat Anda ekstrak menggunakan parser yang berbeda, seperti ekspresi reguler, atau bahkan probe ad hoc yang mencari fitur data.

Sedangkan untuk membaca atau menulis data, mungkin berguna untuk memiliki sistem file dalam memori yang memungkinkan Anda untuk menjalankan tes Anda tanpa kemungkinan gangguan dari bagian lain dari sistem. Jika Anda tidak memiliki akses ke sistem file dalam memori yang baik, gunakan pohon direktori sementara.

BobDalgleish
sumber
1

Gunakan injeksi ketergantungan dan ejekan.

Anda tidak ingin menguji driver SQL Anda dan Anda tidak ingin menguji apakah database SQL Anda online dan diatur dengan benar. Itu akan menjadi bagian dari uji integrasi atau sistem. Anda ingin menguji apakah kode Anda mengirimkan pernyataan SQL yang seharusnya dikirim dan jika ia menginterpretasikan respons seperti yang seharusnya.

Jadi ketika Anda memiliki metode / kelas yang seharusnya melakukan sesuatu dengan basis data, jangan memilikinya dapatkan koneksi basis data itu sendiri. Ubahlah sehingga objek yang mewakili koneksi database diteruskan ke sana.

Dalam kode produksi Anda, lulus objek database yang sebenarnya.

Dalam pengujian unit Anda, lulus objek tiruan yang hanya berperilaku seperti database aktual tidak benar-benar menghubungi server database. Periksalah apakah ia menerima pernyataan SQL yang seharusnya diterimanya dan kemudian merespons dengan tanggapan yang dikodekan dengan keras.

Dengan cara ini Anda dapat menguji lapisan abstraksi basis data Anda tanpa memerlukan basis data yang sebenarnya.

Philipp
sumber
Devil's Advocate: Bagaimana Anda tahu pernyataan SQL mana yang "seharusnya diterima"? Bagaimana jika driver DB mengoptimalkan urutan dari apa yang muncul dalam kode?
user949300
@ user949300 Objek tiruan basis data biasanya menggantikan driver basis data.
Philipp
ketika Anda menguji repositori, tidak ada gunanya menyuntikkan klien database yang diejek. Anda harus menguji bahwa kode Anda menjalankan sql yang berfungsi pada database. jika tidak, Anda hanya akan menguji mock Anda
Ewan
@ Ewan Bukan itu tentang pengujian unit. Tes unit menguji satu unit kode, terisolasi dari bagian dunia lainnya. Anda tidak menguji interaksi antara komponen, seperti kode Anda dan database. Untuk itulah pengujian integrasi.
Philipp
Iya. im mengatakan tidak ada unit titik yang menguji repositori db. uji integrasi adalah satu-satunya hal yang layak dilakukan
Ewan
0

Jika Anda menggunakan pemetaan relasional objek, biasanya ada pustaka terkait yang dapat digunakan untuk menguji apakah pemetaan Anda bekerja dengan benar dengan membuat agregat, bertahan, dan memuatnya kembali dari sesi baru, diikuti dengan verifikasi status terhadap objek aslinya.

NHibernate menawarkan Pengujian Spesifikasi Persistensi . Ini dapat dikonfigurasikan untuk bekerja melawan penyimpanan dalam memori untuk pengujian unit cepat.

Jika Anda mengikuti versi paling sederhana dari pola Repositori dan Unit Kerja, dan menguji semua pemetaan Anda, Anda dapat mengandalkan hal-hal yang berfungsi dengan baik.

pnschofield
sumber