Bagaimana saya bisa menggunakan tes unit dan TDD untuk menguji aplikasi yang sebagian besar bergantung pada operasi CRUD database?

22

Di tempat kerja, salah satu proyek saya kebanyakan tentang mengambil data yang diteruskan dari klien eksternal dan bertahan dalam database. Ini adalah aplikasi Java enterprise yang menggunakan JPA dan sebagian besar logika kami berkisar pada operasi CRUD.

Mayoritas bug kami melibatkan JPA dengan satu atau lain cara.

  • Contoh 1: Jika Anda mengklik tombol simpan dua kali, JPA mungkin mencoba memasukkan entitas yang sama ke dalam database untuk kedua kalinya, menyebabkan pelanggaran kunci primer.
  • Contoh 2: Anda mengambil entitas dari database, mengeditnya dan mencoba memperbarui datanya. JPA dapat mencoba membuat instance baru alih-alih memperbarui yang lama.

Seringkali solusinya perlu menambah / menghapus / mengubah anotasi JPA. Lain waktu ada hubungannya dengan memodifikasi logika DAO.

Saya tidak tahu bagaimana cara mendapatkan kepercayaan pada kode kami menggunakan unit test dan TDD. Saya tidak yakin apakah itu karena unit test dan TDD cocok, atau jika saya mendekati masalahnya salah.

Tes unit sepertinya tidak cocok karena saya hanya dapat menemukan masalah ini saat runtime dan saya perlu menggunakan server aplikasi untuk mereproduksi masalah. Biasanya database perlu dilibatkan yang saya anggap berada di luar definisi uji unit: Ini adalah tes integrasi.

TDD sepertinya kurang pas karena putaran + tes umpan balik sangat lambat sehingga membuat saya sangat tidak produktif. Putaran umpan balik penerapan + pengujian membutuhkan waktu lebih dari 3 menit, dan itu hanya jika saya menjalankan tes secara khusus tentang kode yang saya tulis. Untuk menjalankan semua tes integrasi, dibutuhkan 30+ menit.

Ada kode di luar cetakan ini dan saya selalu menguji unit kapan pun saya bisa. Tetapi sebagian besar bug kami dan time sink terbesar selalu melibatkan JPA atau database.


Ada pertanyaan lain yang serupa , tetapi jika saya mengikuti saran saya akan membungkus bagian yang paling tidak stabil dari kode saya (JPA) dan menguji semuanya kecuali itu. Dalam konteks pertanyaan saya, saya akan berada dalam situasi buruk yang sama. Apa langkah selanjutnya setelah membungkus JPA? IMO pertanyaan itu (mungkin) langkah untuk menjawab pertanyaan saya, tetapi bukan jawaban untuk itu.

Daniel Kaplan
sumber
4
Apa yang Anda lakukan pada dasarnya adalah tes integrasi, karena Anda harus mengatur database untuk benar-benar menguji. Saya bisa membayangkan bahwa satu modul akan bergantung pada yang lain sehingga membuatnya lebih seperti tes integrasi. Saya akan mengubah pertanyaan Anda tentang cara menerapkan pendekatan TDD ke aplikasi Anda.
InformedA
@randomA benar, saya mengedit pertanyaan saya untuk secara eksplisit mengatakan itu. Saya tidak mengerti mengapa Anda merekomendasikan saya mengubah pertanyaan. Bisakah Anda menguraikan? Saya ingin menjaga bagian unit test di sana karena saya lebih suka menulis unit test daripada tes integrasi (walaupun saya sadar itu unit testing != TDD)
Daniel Kaplan
tidak ada yang istimewa, hanya menempatkan TDD di sana. Jika Anda memiliki unit-test di sana, maka banyak orang akan berpikir Anda tidak mengerti hal, dll. Tidak baik untuk Anda ..
InformedA

Jawaban:

7

Salah satu opsi adalah menggunakan database pengujian di-memori seperti H2 ; ini cenderung sekitar 10x lebih cepat dari database menggunakan disk standar, dan dengan waktu startup / teardown yang lebih rendah.

Apakah itu akan membantu memang sangat tergantung pada apakah masalah JPA yang Anda alami cukup umum sehingga mereka akan gagal pada database yang berbeda. Tidak banyak gunanya menjalankan tes lebih cepat jika mereka melewatkan sebagian besar masalah.

Tetapi jika Anda dapat melakukan 10 kali berjalan dengan H2 untuk setiap orang dengan sistem penuh, itu bisa membuahkan hasil.

soru
sumber
Itu pemikiran yang bagus, tapi saya masih harus menyebarkan ke server aplikasi, AFAIK. Itu banyak dari 3+ menit. Yang mengatakan, itu pasti layak dilakukan. Tetapi masih sulit membayangkan menjalankan tes sesering saya menjalankan tes unit dan oleh karena itu tampaknya tidak efisien untuk dikembangkan menggunakan TDD.
Daniel Kaplan
1
Saya pikir biasanya ada cara di sekitar persyaratan itu (mis. Docs.oracle.com/middleware/1212/toplink/TLADG/testingjpa.htm ). Peluang yang cukup besar untuk menjadi lebih banyak pekerjaan daripada dibenarkan; Pilihan lain adalah mendapatkan beberapa server pengujian yang lebih canggih dan menjalankan berbagai hal secara paralel.
soru
1
@tieTYT Bukti konsep saya sendiri dengan unit hsqldb menguji aplikasi web mentah di github: TestingWithHsqldb - unit test tidak memerlukan aplikasi yang akan digunakan.
3

Database bisa sangat mudah untuk unit test - Anda memerlukan prosedur dan transaksi yang tersimpan.

Ini yang dikatakan Microsoft tentang pengujian unit Database . Anda juga dapat menjalankan tes unit terhadap basis data, menulis tes Anda di Java atau C # dengan mengatur koneksi DB, memulai transaksi, menulis data apa pun yang ingin Anda gunakan untuk tes ke DB, menjalankan tes dan kemudian rollback. Tidak ada kerusakan pada DB jika Anda menggunakannya, Anda juga menggunakan dan Anda mendapatkan tes sepenuhnya terisolasi.

Semoga ini bisa memberi Anda wawasan bagaimana melakukannya dalam kerangka kerja Anda.

gbjbaanb
sumber
Seperti yang saya katakan, "Sebagian besar bug kami melibatkan JPA dalam satu atau lain cara.", Saya pikir saran artikel akan melewatkan semua itu. Juga, jika Anda menganggap tes Java / C # tersebut masih menjadi unit test, kami memiliki definisi yang sangat berbeda. Saya pikir ini adalah saran yang baik secara umum, tetapi sepertinya masih akan membutuhkan banyak waktu untuk menyebarkan dan menjalankan suite dan karena itu tidak kondusif untuk TDD. Apakah Anda tidak setuju?
Daniel Kaplan
Kami biasa menjalankan tes unit DB untuk SQL kami, tetapi kemudian semuanya dalam sprocs. Sementara Anda dapat Unit direktori test sql dari prosedur sql lain, kerangka unit uji kami adalah MSTest sehingga masuk akal untuk menjalankan mereka dari sana (Hei, kami mendapat kutu hijau di membangun server yang yang faktor yang paling penting). Jika Anda memiliki DB yang selalu aktif (dan kami melakukannya untuk pengujian int), maka mudah untuk mengunggah semua kode sql dan menjalankan semua tes unit pada server build. Terkadang Anda hanya perlu pragmatis tentang hal-hal ini.
gbjbaanb
Saya tidak berpikir Anda menanggapi kalimat pertama saya.
Daniel Kaplan
baik, gunakan saja unit-jpa saja. Saya tidak bisa menjawab bagaimana kode JPA Anda bekerja (atau tidak), hanya mencoba memberi Anda beberapa ide untuk mendapatkan sql yang diuji di db.
gbjbaanb
3

Orang lain telah menjawab dengan "Mock out DB Anda!" - tapi apa gunanya mengejek lapisan DB Anda jika Anda benar-benar perlu menguji bagaimana itu berinteraksi dengan kode Anda?

Apa yang Anda cari adalah tes integrasi dan / atau tes UI otomatis. Anda menyebutkan bahwa masalah terjadi ketika:

*If you click the save button twice*

Satu-satunya cara untuk menguji ini adalah dengan menulis tes UI otomatis untuk mengklik tombol dua kali. Mungkin periksa Selenium.

Anda mungkin juga akan membutuhkan unit pengujian DB dan untuk pengujian Anda arahkan ke sana. Rasa sakit untuk dipertahankan tetapi selamat datang di TDD di dunia nyata.

Rocklan
sumber
ini berbunyi lebih seperti kata-kata kasar daripada jawaban
nyamuk
Saya telah menjawab pertanyaan itu tiga kali - tes integrasi, tes GUI dan / atau unit yang menguji DB. Ya itu sedikit kata-kata kasar, saya akan mengeditnya untuk beberapa kewarasan sekarang.
Rocklan
1
"Satu-satunya cara untuk menguji ini adalah dengan menulis tes UI otomatis untuk mengklik tombol dua kali. Mungkin memeriksa Selenium." Dalam situasi seperti itu, backend sebaiknya mencegah hal itu terjadi, jika tidak UI akan memiliki akses langsung ke database.
Daniel Kaplan
0

Dalam contoh yang Anda berikan dalam pertanyaan Anda, Anda tidak dapat menguji unit / TDD jalan Anda ke dalam situasi mengklik tombol dua kali untuk menyebabkan kesalahan dengan sangat mudah. Tetapi apa yang dapat Anda uji unit adalah bahwa dalam kode yang dipanggil ketika Anda mengklik tombol, jika Anda mendapatkan pengecualian dari lapisan kegigihan Anda menanganinya dengan tepat (dengan mengejek lapisan persistensi atau dengan menggunakan database dalam memori sebagai telah disarankan dalam jawaban lain) - baik dengan memikirkan kembali atau menampilkan kesalahan atau apa pun.

Anda benar bahwa TDD dapat mulai mogok ketika Anda perlu melakukan tes yang tidak cocok untuk tes unit (yaitu tes integrasi / sistem) - ini membentuk cukup banyak diskusi dalam "Is TDD" baru-baru ini. Mati?" perdebatan antara Kent Beck, Martin Fowler dan David Heinemeier Hansson: http://martinfowler.com/articles/is-tdd-dead/

Chris Cooper
sumber