Ketika pengujian melalui metode publik mulai bau (contoh)

Dalam artikel tentang pengujian metode publik, saya menyinggung pengujian unit logika kelas pribadi. Saya pikir akan bermanfaat untuk mengulangi tesis ini, karena mayoritas, menurut pendapat saya, merasa bahwa kita berbicara tentang pengujian metode pribadi, meskipun itu tentang logika pribadi. Pada artikel ini saya ingin menggambarkan tesis utama dengan contoh praktis. Di bawah kat contoh dengan sedikit analisis.

Contoh stok


Untuk mengilustrasikan masalahnya, saya memberikan sebuah contoh. Idenya diambil dari satu proyek nyata. Idealnya, seperti seseorang mungkin memperhatikan, kelas harus ditulis berbeda. Tetapi sekarang tidak ada yang akan menulis ulang (atau refactor), karena ini akan menghabiskan banyak waktu untuk mengedit dan menguji apa yang berhasil. Karena itu, tidak akan disetujui. Dalam hal ini, Anda perlu mengubah kode dan perubahan harus benar. Jadi, ini kodenya. Logika penting terkonsentrasi dalam metode ProcessMessage. Tujuan: Untuk memperkenalkan bendera baru logika bisnis dalam pemrosesan pesan. Bendera ini memiliki logika non-sepele.

Bagaimana Anda menerapkan dan menguji bendera?

using System; using System.Threading.Tasks; using System.Threading; using System.Messaging; namespace PublicMethodNottrivialSample { public class MessageProcessorService { private object _lockObject = new object(); private CancellationTokenSource _cancellationSource; private Action _receiveMessage; private int _listenerThreads = 5; public void Start() { lock (_lockObject) { _cancellationSource = new CancellationTokenSource(); Task.Factory.StartNew(() => InitializeReceiveLoop(_cancellationSource.Token), _cancellationSource.Token); } } private void InitializeReceiveLoop(CancellationToken cancellationToken) { _receiveMessage = () => { while (!cancellationToken.IsCancellationRequested) { using (MessageQueueTransaction msgTx = new MessageQueueTransaction()) { try { msgTx.Begin(); //   MessageQueue queue = new MessageQueue(); Message message = queue.Receive(msgTx); //    ,    if (!cancellationToken.IsCancellationRequested) { ProcessMessage(message); } msgTx.Commit(); } catch (Exception ex) { // some logging } } } }; for (int n = 0; n < _listenerThreads; n++) { StartProcessingLoop(cancellationToken); } } private void ProcessMessage(Message message) { //   ,     } private void StartProcessingLoop(CancellationToken cancellationToken) { Task.Factory.StartNew(_receiveMessage, cancellationToken); } } } 

Kelas menunjukkan bahwa satu-satunya metode publik adalah Mulai (). Anda dapat mengujinya jika Anda mengubah tanda tangan, tetapi dalam hal ini antarmuka publik akan berubah. Selain itu, Anda perlu mengubah beberapa metode untuk mengembalikan utas yang sedang berjalan dan kemudian menunggu sampai selesai dalam pengujian.

Tetapi, seperti yang kita ingat, persyaratan hanya menyangkut implementasi bendera dalam proses pemrosesan pesan, dan tidak menyiratkan perubahan dalam pengoperasian mekanisme penerimaan pesan. Oleh karena itu, tidak peduli siapa yang membuat perubahan, saya akan berharap bahwa hanya satu metode yang akan diperbaiki, dan unit test hanya akan berhubungan dengan logika yang bisa berubah. Untuk mencapai ini, tetap dalam kerangka prinsip itu sulit: tes akan berubah menjadi non-sepele, yang akan memerlukan baik penolakan untuk menulisnya, atau kode yang rumit. Inilah cara pengujian dimulai melalui metode publik. Dan kemudian seseorang akan secara emosional menulis: "TDD adalah waktu yang lama", "Pelanggan tidak membayar", atau "Tes tidak berfungsi dengan baik".

Secara umum, perlu untuk menguji kode seperti itu, tetapi tidak dengan tes unit, tetapi dengan tes integrasi.

"Kamu catur, atau pergi"


Tentu saja, menulis tes unit untuk logika yang diubah diperlukan. Saya percaya bahwa dilema, dalam hal ini, adalah memilih cara yang paling murah untuk menulis tes, daripada kode yang berguna. Di sini saya maksudkan fakta bahwa apa pun yang Anda lakukan: refactoring untuk metode publik atau solusi lain - Anda akan melakukan ini untuk menulis tes, dan tidak menyelesaikan persyaratan dari tugas klien. Dalam hal ini, disarankan untuk mengevaluasi biaya dan efek. Selain solusi di atas dengan refactoring, ada beberapa solusi alternatif. Saya bawa semuanya, di bawah ini kita akan membahas Pro dan Kontra:

  1. metode pribadi dapat diuji
  2. dapatkah metodenya dipublikasikan
  3. dapat dibuat internal
  4. dapat ditarik ke dalam kelas terpisah sebagai metode publik

Jika kita membandingkan tiga metode pertama dengan solusi melalui metode publik, tetapi semuanya membutuhkan lebih sedikit biaya tenaga kerja (dengan swasta bukan fakta). Juga, mereka semua, pada kenyataannya, adalah solusi yang sama, dengan sedikit perbedaan gaya. Karena hasilnya akan diperoleh dengan cara apa pun, oleh karena itu, menurut pendapat saya, pilihan yang mendukung salah satu solusi ini tidak boleh didasarkan pada kemampuan teknis bahasa, tetapi pada apa yang ingin Anda tunjukkan kepada pengembang lain:

  1. jika metode ini dapat dijalankan dari mana saja dalam solusi dan itu adalah bagian dari perilaku kelas, maka buat itu publik dan tarik ke antarmuka kelas;
  2. jika metode ini dapat digunakan dari kelas lain, tetapi hanya di dalam majelis ini, maka lakukan internal ;
  3. jika metode hanya dapat digunakan di dalam kelas utama, di mana ia dapat dipanggil dari metode lain, maka buatlah itu terlindungi internal .

Metode internal dapat dibuat terlihat oleh majelis uji menggunakan atribut InternalsVisibleTo dan dipanggil seperti biasa. Pendekatan ini membuat tes menulis lebih mudah, dan hasilnya akan sama.

Menguji ProsesMessage


Mari kita kembali ke tugas. Mengikuti pendekatan di atas, saya akan membuat beberapa perubahan:

  • akan membuat ProcessMessage publik
  • akan membuat metode internal baru yang dilindungi untuk logika bendera (mis. GetFlagValue)
  • akan menulis tes untuk GetFlagValue untuk semua kasus
  • Saya akan menulis tes untuk ProcessMessage untuk memastikan bahwa GetFlagValue digunakan dengan benar: parameter dilewatkan dengan benar dan benar-benar digunakan

Saya akan mengklarifikasi bahwa saya tidak akan menulis tes unit untuk semua kasus menggunakan GetFlagValue dalam metode ProcessMessage, asalkan saya menguji kasus ini dalam tes unit GetFlagValue. Dalam kasus yang tidak ditemukan, mereka harus ditambahkan. Dalam hal ini, pendekatan utama tetap:

  • semua kasus dicakup oleh tes unit GetFlagValue
  • Tes unit ProcessMessage memverifikasi bahwa metode flag digunakan dengan benar

Saya percaya bahwa sesuai dengan ini, Anda dapat menulis hanya satu unit test untuk ProcessMessage dan beberapa untuk GetFlagValue.

Sesuatu seperti itu. Pendapat anda

Source: https://habr.com/ru/post/id420567/


All Articles