Bagaimana Anda menulis tes untuk kode yang tergantung pada implementasi eksternal konkret yang tidak dapat diejek?

17

Latar Belakang: Saya berpikir untuk mencoba memperkenalkan konsep unit test kepada rekan kerja saya dengan membuat beberapa untuk modul yang telah saya kerjakan; persyaratannya baru-baru ini berubah dan memerlukan beberapa abstraksi / interaksi lagi sehingga sepertinya cara yang baik untuk mengembangkan serangkaian tes yang akan "membuktikan" kerjanya tanpa harus menyodok aplikasi secara manual.

Masalahnya, bagaimanapun, adalah bahwa modul bergantung pada faktor-faktor eksternal yang tidak dapat digerakkan yaitu PDF dan XSL. Pada dasarnya saya membaca XML dari basis data dan menerapkan transformasi XSL ke dalamnya, lalu mengonversinya ke PDF menggunakan pustaka yang disebut ABCPDF. PDF ini kemudian digabungkan dengan PDF lain berdasarkan templat statis. Saya tahu bahwa saya dapat menguji XML dan memastikan nilainya benar, tetapi banyak potensi bug dan masalah terkait dengan tampilan aktual dari dokumen yang sudah selesai - misalnya hal-hal kecil seperti berapa lama string teks dibungkus, di mana area HTML tertentu berada terletak dalam kaitannya dengan dokumen, dll. Apakah mungkin untuk menguji hal-hal ini (saya menyadari ini mungkin tes integrasi atau .. jenis tes ketiga yang namanya saya lupakan [bukan tes Penerimaan, jenis lain], dan bukan unit tes) karena saya tidak bisa, setahu saya, membuat-buat PDF dengan mudah pendek membuatnya kemudian membacanya kembali atau membuat string HTML (yaitu transformasi XML) dan menguraikannya dengan tangan untuk memeriksa keberadaan sel-sel tabel tertentu di hubungan dengan sel tabel lainnya.

Dalam situasi seperti ini, haruskah saya hanya fokus pada unit test untuk memastikan informasi itu benar dan bahwa saya dapat membuat PDF, atau menggabungkannya, atau apa pun dan menggunakan pengujian manual untuk masalah tampilan yang sebenarnya?

Wayne Molina
sumber
6
"faktor eksternal yang tidak dapat digerakkan" adalah petunjuk bahwa Anda tidak melakukan tes unit sejak awal. Itu berarti pengujian integrasi . Yang ingin Anda lakukan? Pengujian unit terhadap kode Anda atau pengujian integrasi untuk hal komposit ini ? Silakan pilih satu atau yang lain, karena sulit untuk membicarakan keduanya sekaligus.
S.Lott
2
Saya tidak membeli "unmockable". Saya akan menerima "bahwa saya tidak tahu bagaimana mengejek", yang berarti bahwa pertanyaan Anda yang sebenarnya adalah "bagaimana saya mengejeknya?".
Rein Henrichs
Mungkin :) Saya terbiasa dengan mengejek XML yang digunakan, tetapi tidak dengan cara mengejek dokumen PDF atau HTML yang sebenarnya di mana format penting.
Wayne Molina
1
Saya pikir maksud Anda tes "fungsional" (ujung ke ujung aplikasi) atau "sistem" (beberapa aplikasi ujung ke ujung)
Gary Rowe
@Gary - Ya, fungsional adalah kata. Saya ingat mereka sekarang dari belajar Rails: model tes Unit, pengontrol tes Fungsional, Integrasi menguji segalanya.
Wayne Molina

Jawaban:

13

Uji fitur, bukan unit

Menggunakan input xml yang dikenal, output PDF dan secara manual (dan cermat) memverifikasi bahwa itu benar. Kemudian simpan sebagai referensi.

Tes di masa depan menggunakan input xml yang sama dapat melakukan perbandingan file biner dengan referensi.

Jika perbandingan tingkat file tidak memuaskan, tampilkan PDF di akhir tes dan ambil tangkapan layar, kemudian lakukan pengujian otomatis dibandingkan dengan tangkapan layar referensi.

Steven A. Lowe
sumber
+1 karena Anda hanya tertarik dengan hasil akhir di level ini. Jika Anda mengubah implementasi bagaimana Anda sampai pada mendapatkan PDF Anda tidak harus mengubah tes fungsional Anda.
Gary Rowe
2
+1 untuk saran yang baik, inilah yang kami lakukan dalam proyek kami saat ini. Kami membuat perangkat khusus untuk melakukan perbandingan PDF, yang memungkinkan kami menghilangkan bagian yang berubah dalam dokumen seperti cap waktu. Peringatan: beralih ke renderer PDF (versi) yang berbeda dapat menyebabkan perubahan tata letak yang halus, menyebabkan perbandingan biner langsung dengan sinyal tumpukan positif palsu.
Péter Török
5

Biasanya dalam kasus seperti ini Anda abstrak semua yang Anda tidak dapat menguji di balik implementasi yang dapat Anda gunakan dengan antarmuka. Saya hanya akan melakukan sesuatu yang konyol seperti pembangun PDF karena tampaknya masuk akal.

public class PdfBuilder : IPdfBuilder
{
  public byte[] BuildPdf(...)
  {
    // actual untestable code here
  }
}

public interface IPdfBuilder
{
  byte[] BuildPdf(...);
}

Anda kemudian dapat mengejek IPdfBuilder dalam tes Anda untuk melakukan apa pun yang Anda inginkan. Ini seringkali berarti Anda harus mulai menggunakan wadah IoC ( /programming/871405/why-do-i-need-an-ioc-container-as-opposed-to-stalletforward-di-code dan /programming/21288/which-net-dependency-injection-frameworks-are-worth-looking-into sebagai tempat untuk memulai) jika Anda tidak menggunakannya sekarang.

Dan tes yang bukan tes unit sering disebut tes integrasi. Tes integrasi yang rumit sering kali tidak sepenuhnya sepadan, sehingga Anda hanya mengabstraksi bagian itu dan mengurangi jumlah logika bisnis dalam abstraksi itu sehingga Anda bisa mengujinya dalam unit test.

Beri tahu saya jika ini tidak sepenuhnya jelas.

Travis
sumber
+1 untuk menyembunyikan kode yang tidak dapat diuji. Kemudian Anda dapat melakukan tes manual hingga Anda mengetahui apa yang perlu melintasi antarmuka itu untuk mendapatkan hasil yang tepat, dan tes unit untuk yang dihasilkan dengan benar untuk mendapatkan tes unit regresi Anda.
Ethel Evans
1

Saya membangun sesuatu yang sangat mirip beberapa waktu lalu, dan hanya menggunakan tes visual dasar. Pengujian tidak harus otomatis, jadi tidak ada yang salah dengan hanya mencari hasil yang diharapkan (jelas, dalam berbagai situasi yang telah ditentukan sebelumnya). Seringkali, sebuah gambar bernilai ribuan tes di mana visual yang bersangkutan . Saya menggunakan pengujian unit otomatis secara luas, tapi saya pikir beberapa orang bisa sedikit terbawa ketika masuk ke pengujian GUI, atau apa pun visual IMHO. Dengan produk tertentu, saya mengakui bahwa pendekatan "cukup baik" ini tidak akan cukup jadi YMMV.

Namun, saya akan sedikit khawatir tentang eksternalitas yang tidak dapat digerakkan. Ini bisa menjadi tanda kopling ketat, yang bagus untuk dihindari sebagai aturan umum, tapi saya tidak akan berspekulasi terlalu banyak pada kode Anda dalam hal itu tanpa rincian lebih lanjut.

Morgan Herlocker
sumber
Ini sangat erat digabungkan tetapi itu adalah area yang tidak dapat saya perbaiki karena tidak ada dukungan untuk membuatnya digabungkan secara longgar dan tidak ada sumber daya yang ditujukan untuk refactoring (tapi itu adalah serangkaian masalah yang berbeda).
Wayne Molina