Haruskah seseorang menguji nilai enum menggunakan unit test?


15

Jika Anda memiliki enum dengan nilai saja (tidak ada metode yang dapat dilakukan di Jawa), dan enum ini adalah bagian dari definisi bisnis sistem, haruskah seseorang menulis unit test untuknya?

Saya berpikir bahwa mereka harus ditulis, bahkan jika itu bisa terlihat sederhana dan berlebihan saya menganggap bahwa apa yang menjadi perhatian spesifikasi bisnis harus dibuat secara eksplisit ditulis dalam sebuah tes, apakah itu dengan unit / integrasi / ui / etc. menguji atau dengan menggunakan sistem jenis bahasa sebagai metode pengujian. Karena nilai-nilai yang harus dimiliki oleh enum (misalnya di Jawa), dari sudut pandang bisnis, tidak dapat diuji menggunakan sistem tipe, saya pikir harus ada unit test untuk itu.

Pertanyaan ini tidak mirip dengan yang ini karena tidak membahas masalah yang sama dengan saya. Dalam pertanyaan itu ada fungsi bisnis (savePeople) dan orang tersebut bertanya tentang implementasi internal (forEach). Di sana, ada lapisan bisnis tengah (fungsi menyelamatkan orang) merangkum konstruksi bahasa (forEach). Di sini bahasa konstruk (enum) adalah yang digunakan untuk menentukan perilaku dari sudut pandang bisnis.

Dalam hal ini detail implementasi bertepatan dengan "sifat alami" dari data, yaitu: satu set (dalam arti matematika) nilai. Anda bisa saja menggunakan set yang tidak dapat diubah, tetapi nilai yang sama tetap ada di sana. Jika Anda menggunakan array, hal yang sama harus dilakukan untuk menguji logika bisnis. Saya pikir teka-teki di sini adalah fakta bahwa konstruk bahasa bertepatan sangat baik dengan sifat data. Saya tidak yakin apakah saya sudah menjelaskan diri sendiri dengan benar


19
Seperti apa tepatnya tes unit enum?
jonrsharpe


@jonrsharpe Ini akan menegaskan bahwa nilai-nilai yang ada di dalam enum adalah yang Anda harapkan. Saya akan melakukannya dengan mengulangi nilai-nilai enum, menambahkannya ke set, misalnya sebagai string. Memesan set itu. Perbandingan yang ditetapkan terhadap daftar nilai yang diurutkan ditulis dengan tangan dalam tes. Mereka harus cocok.
IS1_SO

1
@jonrsharpe, saya suka menganggap unit test juga sebagai "definisi" atau "persyaratan" yang ditulis dalam kode. Tes unit enum akan sesederhana memeriksa jumlah item pada enum dan nilainya. Khususnya dalam C #, di mana enum bukan kelas, tetapi dapat langsung dipetakan ke bilangan bulat, menjamin nilai-nilainya dan bukan pemrograman secara kebetulan mungkin terbukti berguna untuk keperluan serialisasi.
Machado

2
IMHO itu tidak jauh lebih berguna daripada menguji jika 2 + 2 = 4 untuk memeriksa apakah Semesta benar. Anda menguji kode menggunakan enum itu, bukan enum itu sendiri.
Agent_L

Jawaban:


39

Jika Anda memiliki enum dengan nilai saja (tidak ada metode yang dapat dilakukan di Jawa), dan enum ini adalah bagian dari definisi bisnis sistem, haruskah seseorang menulis unit test untuknya?

Tidak, mereka hanya negara.

Pada dasarnya, fakta bahwa Anda menggunakan enum adalah detail implementasi ; itulah hal yang mungkin ingin Anda ubah menjadi desain yang berbeda.

Pengujian enum untuk kelengkapan adalah analog dengan pengujian bahwa semua bilangan bulat yang representatif hadir.

Namun, menguji perilaku yang didukung oleh enumerasi adalah ide yang bagus. Dengan kata lain, jika Anda mulai dari test suite yang lulus, dan mengomentari nilai enum tunggal, maka setidaknya satu tes harus gagal (kesalahan kompilasi dianggap gagal).


5
Tetapi dalam kasus ini detail implementasi bertepatan dengan "sifat alami" dari data, yaitu: satu set (dalam arti matematika) dari nilai-nilai. Anda bisa saja menggunakan set yang tidak dapat diubah, tetapi nilai yang sama tetap ada di sana. Jika Anda menggunakan array, hal yang sama harus dilakukan untuk menguji logika bisnis. Saya pikir teka-teki di sini adalah fakta bahwa konstruk bahasa bertepatan sangat baik dengan sifat data. Saya tidak yakin apakah saya sudah menjelaskan diri sendiri dengan benar.
IS1_SO

4
@ IS1_SO - ke titik VOU bahwa satu tes harus gagal: apakah itu? Dalam hal ini, Anda tidak perlu menguji Enum secara khusus. Bukan? Mungkin itu tanda bahwa Anda bisa model kode Anda lebih sederhana dan membuat abstraksi atas 'sifat sejati' dari data - misalnya terlepas dari kartu di dek, apakah Anda benar-benar harus memiliki representasi [ Hearts, Spades, Diamonds, Clubs] jika Anda hanya kartu jika kartu merah / hitam?
anotherdave

1
@ IS1_SO katakanlah Anda memiliki enum kode kesalahan, dan Anda ingin melempar null_ptrkesalahan. Sekarang memiliki kode kesalahan melalui enum. Kode yang memeriksa null_ptrkesalahan mencari kode melalui enum juga. Jadi mungkin memiliki nilai 5(untuk ex). Sekarang Anda perlu menambahkan kode kesalahan lain. Enum diubah (misalkan kita menambahkan yang baru ke bagian atas enum) Nilai null_ptrsekarang 6. Apakah ini masalah? Anda sekarang mengembalikan kode kesalahan 6dan menguji 6. Selama semuanya konsisten secara logis, Anda baik-baik saja, meskipun ada perubahan yang melanggar tes teoretis Anda.
Baldrickk

17

Anda tidak menguji deklarasi enum . Anda dapat menguji apakah input / output fungsi memiliki nilai enum yang diharapkan. Contoh:

enum Parity {
    Even,
    Odd
}

Parity GetParity(int x) { ... }

Anda tidak menulis tes verifikasi lalu enum Paritymenentukan nama Evendan Odd. Tes semacam itu tidak ada gunanya karena Anda hanya akan mengulangi apa yang sudah dinyatakan oleh kode. Mengatakan hal yang sama dua kali tidak membuatnya lebih benar.

Anda melakukan tes tulis verifikasi GetParitymengatakan akan kembali Evenuntuk 0, Odd1 dan seterusnya. Ini berharga karena Anda tidak mengulangi kode, Anda memverifikasi perilaku kode, terlepas dari penerapannya. Jika kodenya di dalamGetParity sepenuhnya ditulis ulang, tes akan tetap valid. Memang manfaat utama dari unit test adalah mereka memberi Anda kebebasan untuk menulis ulang dan kode refactor dengan aman, dengan memastikan kode tersebut masih berfungsi seperti yang diharapkan.

Tetapi jika Anda memiliki tes yang memastikan deklarasi enum mendefinisikan nama yang diharapkan, maka setiap perubahan yang Anda buat pada enum di masa depan akan mengharuskan Anda untuk mengubah tes juga. Ini berarti tidak hanya dua kali lebih banyak pekerjaan, itu juga berarti manfaat apa pun untuk unit test hilang. Jika Anda harus mengubah kode dan menguji pada saat yang sama , maka tidak ada perlindungan terhadap bug yang diperkenalkan.


Saya telah memperbarui pertanyaan saya dalam upaya untuk menjawab jawaban ini, periksa untuk mengetahui apakah itu membantu.
IS1_SO

@ IS1_SO: OK yang membingungkan saya - apakah Anda secara dinamis menghasilkan nilai enum, atau apa yang terjadi?
JacquesB

Tidak. Maksud saya adalah bahwa dalam hal ini konstruk bahasa yang dipilih untuk mewakili nilai-nilai adalah enum. Tapi seperti yang kita tahu itu adalah detail implementasi. Apa yang terjadi jika seseorang memilih array, atau Set <> (dalam Java) atau string dengan beberapa token pemisahan untuk mewakili nilai? Jika itu masalahnya maka masuk akal untuk menguji bahwa nilai-nilai yang terkandung adalah yang menarik bagi bisnis. Itu poin saya. Apakah penjelasan ini membantu?
IS1_SO

3
@ IS1_SO: Apakah Anda berbicara tentang pengujian instance enum yang dikembalikan dari fungsi memiliki nilai yang diharapkan? Karena ya Anda bisa mengujinya. Anda tidak perlu menguji deklarasi enum itu sendiri.
JacquesB

11

Jika ada risiko bahwa mengubah enum akan merusak kode Anda maka yakin, apa pun dengan atribut [Bendera] di C # akan menjadi kasus yang baik karena menambahkan nilai antara 2 dan 4 (3) akan menjadi bitwise 1 dan 2 daripada bit item rahasia.

Itu adalah lapisan perlindungan.

Anda harus mempertimbangkan memiliki kode praktik enum yang sudah dikenal semua pengembang. Jangan mengandalkan representasi tekstual dari enum adalah hal yang umum, tetapi ini mungkin bertentangan dengan pedoman serialisasi Anda.

Saya telah melihat orang "memperbaiki" kapitalisasi entri enum, mengurutkannya berdasarkan abjad atau dengan beberapa pengelompokan logis lainnya yang semuanya memecah bit kode buruk lainnya.


5
Jika nilai numerik enum digunakan di mana saja, misalnya saat disimpan dalam database, maka penataan ulang (termasuk menghapus atau menyisipkan sebelum nilai terakhir) dapat menyebabkan catatan yang ada menjadi tidak valid.
stannius

3
+1, jawaban ini diremehkan. Jika enum Anda merupakan bagian dari serialisasi, antarmuka input dengan kata eksternal atau informasi yang dapat digabungkan bitwise, mereka pasti perlu diuji konsistensi pada setiap versi sistem. Setidaknya jika Anda khawatir tentang kompatibilitas ke belakang, yang biasanya merupakan hal yang baik.
Machado

11

Tidak, tes yang memeriksa bahwa enum berisi semua nilai yang valid dan tidak lebih dari dasarnya mengulangi deklarasi enum. Anda hanya akan menguji bahwa bahasa mengimplementasikan enum construct dengan benar yang merupakan tes tidak masuk akal.

Yang sedang berkata, Anda harus menguji perilaku yang tergantung pada nilai enum. Misalnya, jika Anda menggunakan nilai enum untuk membuat cerita bersambung entitas untuk json atau apa pun, atau menyimpan nilai-nilai dalam database, Anda harus menguji perilaku untuk semua nilai enum. Dengan begitu, jika enum dimodifikasi setidaknya salah satu tes harus gagal. Bagaimanapun, yang akan Anda uji adalah perilaku di sekitar enum Anda, bukan deklarasi enum itu sendiri.


3

Kode Anda harus bekerja dengan benar, terlepas dari nilai aktual enum. Jika itu masalahnya, maka tidak diperlukan unit test.

Tetapi Anda mungkin memiliki kode tempat mengubah nilai enum akan merusak sesuatu. Misalnya, jika nilai enum disimpan dalam file eksternal, dan setelah mengubah nilai enum membaca file eksternal akan memberikan hasil yang salah. Dalam hal ini Anda akan memiliki komentar BESAR di dekat enum yang memperingatkan siapa pun untuk tidak mengubah nilai apa pun, dan Anda dapat menulis unit test yang memeriksa nilai numerik.


1

Secara umum, hanya memeriksa bahwa enum memiliki daftar nilai yang dikodekan dengan keras tidak bernilai banyak, seperti jawaban yang lain, karena Anda hanya perlu memperbarui tes dan enum bersama.

Saya pernah punya case bahwa satu modul menggunakan tipe enums dari dua modul lain dan memetakannya. (Salah satu enum memiliki logika tambahan dengannya, yang lain adalah untuk akses DB, keduanya memiliki dependensi yang harus diisolasi satu sama lain.)

Dalam hal ini, saya menambahkan tes (dalam modul pemetaan) yang memverifikasi bahwa semua entri enum di enum sumber juga ada di target enum (dan dengan demikian, pemetaan akan selalu berfungsi). (Untuk beberapa kasus saya juga memeriksa sebaliknya.)

Dengan cara ini, ketika seseorang menambahkan entri enum ke salah satu enum dan lupa menambahkan entri yang sesuai ke yang lain, tes mulai gagal.


1

Enum adalah tipe terbatas, dengan nama khusus (semoga bermakna). Enum mungkin hanya memiliki satu nilai, seperti voidyang hanya berisi null(beberapa bahasa menyebutnya unit, dan menggunakan nama voiduntuk enum tanpa elemen!). Ini mungkin memiliki dua nilai, seperti boolyang memiliki falsedan true. Mungkin ada tiga, seperti colourChanneldengan red, greendan blue. Dan seterusnya.

Jika dua enum memiliki jumlah nilai yang sama, maka keduanya "isomorfik"; yaitu jika kita mengganti semua nama secara sistematis maka kita dapat menggunakan satu di tempat yang lain dan program kita tidak akan berperilaku berbeda. Secara khusus, tes kami tidak akan berlaku berbeda!

Misalnya, resultmengandung win/ lose/ drawisomorfis di atas colourChannel, karena kita dapat mengganti mis colourChanneldengan result, reddengan win, greendengan losedan bluedengan draw, dan selama kita melakukannya di mana-mana (produsen dan konsumen, parser dan serialisers, entri basis data, file log, dll. ) maka tidak akan ada perubahan dalam program kami. " colourChannelTes" apa pun yang kami tulis masih akan berlalu, meskipun tidak colourChannelada lagi!

Juga, jika suatu enum mengandung lebih dari satu nilai, kita selalu dapat mengatur ulang nilai-nilai itu untuk mendapatkan enum baru dengan jumlah nilai yang sama. Karena jumlah nilai tidak berubah, pengaturan baru isomorfik dengan yang lama, dan karenanya kami bisa mengganti semua nama dan tes kami masih akan berlalu (perhatikan bahwa kami tidak bisa begitu saja mengubah definisi; kami harus masih alihkan semua situs yang digunakan juga).

Artinya, sejauh menyangkut mesin, enum adalah "nama yang dapat dibedakan" dan tidak ada yang lain . Satu-satunya hal yang dapat kita lakukan dengan enum adalah bercabang pada apakah dua nilai itu sama (misalnya red/ red) atau berbeda (misalnya red/ blue). Jadi itulah satu-satunya hal yang dapat dilakukan 'unit test', misalnya

(  red == red  ) || throw TestFailure;
(green == green) || throw TestFailure;
( blue == blue ) || throw TestFailure;
(  red != green) || throw TestFailure;
(  red != blue ) || throw TestFailure;
...

Seperti yang dikatakan @ jesm00, tes semacam itu memeriksa implementasi bahasa alih-alih program Anda. Tes-tes ini tidak pernah merupakan ide yang baik: bahkan jika Anda tidak mempercayai implementasi bahasa, Anda harus mengujinya dari luar , karena itu tidak dapat dipercaya untuk menjalankan tes dengan benar!

Jadi itulah teorinya; bagaimana dengan praktiknya? Masalah utama dengan karakterisasi enum ini adalah bahwa program 'dunia nyata' jarang mandiri: kami memiliki versi lawas, penyebaran jarak jauh / tertanam, data historis, cadangan, basis data langsung, dll. Sehingga kami tidak pernah bisa benar-benar 'beralih' semua kemunculan nama tanpa kehilangan kegunaan.

Namun hal-hal semacam itu bukanlah 'tanggung jawab' enum itu sendiri: mengubah enum mungkin memutuskan komunikasi dengan sistem jarak jauh, tetapi sebaliknya kita mungkin memperbaiki masalah seperti itu dengan mengubah enum!

Dalam skenario tersebut, enum adalah merah-herring: bagaimana jika satu sistem perlu untuk menjadi ini cara, dan lain perlu untuk menjadi yang cara? Tidak mungkin keduanya, tidak peduli berapa banyak tes yang kami tulis! Penyebab sesungguhnya di sini adalah antarmuka input / output, yang seharusnya menghasilkan / menggunakan format yang didefinisikan dengan baik alih-alih "integer apa pun yang mengambil interpretasi". Jadi solusi sebenarnya adalah menguji antarmuka i / o : dengan unit test untuk memeriksa apakah ia menguraikan / mencetak format yang diharapkan, dan dengan tes integrasi untuk memeriksa apakah format tersebut benar-benar diterima oleh pihak lain.

Kita mungkin masih bertanya-tanya apakah enum sedang 'dilaksanakan dengan cukup menyeluruh', tetapi dalam hal ini enum lagi-lagi merupakan ikan haring merah. Yang sebenarnya kami pedulikan adalah test suite itu sendiri . Kami dapat memperoleh kepercayaan di sini dalam beberapa cara:

  • Cakupan kode dapat memberi tahu kami jika variasi nilai enum yang berasal dari rangkaian uji cukup untuk memicu berbagai cabang dalam kode. Jika tidak, kita dapat menambahkan tes yang memicu cabang yang tidak tertutup, atau menghasilkan variasi enum yang lebih luas dalam pengujian yang ada.
  • Pemeriksaan properti dapat memberi tahu kami jika berbagai cabang dalam kode sudah cukup untuk menangani kemungkinan runtime. Misalnya, jika kode hanya menangani red, dan kami hanya menguji red, maka kami memiliki cakupan 100%. Pemeriksa properti akan (mencoba) menghasilkan contoh tandingan untuk pernyataan kami, seperti menghasilkan greendan bluenilai yang kami lupa uji.
  • Pengujian mutasi dapat memberi tahu kita apakah pernyataan kita benar-benar memeriksa enum, daripada hanya mengikuti cabang dan mengabaikan perbedaannya.

1

Tidak. Tes unit untuk unit pengujian.

Dalam pemrograman berorientasi objek, sebuah unit seringkali merupakan keseluruhan antarmuka, seperti kelas, tetapi bisa berupa metode individual.

https://en.wikipedia.org/wiki/Unit_testing

Tes otomatis untuk enum yang dideklarasikan akan menguji integritas bahasa dan platform yang menjalankannya daripada logika dalam kode yang ditulis oleh pengembang. Tidak ada gunanya untuk tujuan yang berguna - dokumentasi disertakan karena kode yang menyatakan enum berfungsi sebagai dokumentasi sama seperti kode yang akan mengujinya.


0

Anda diharapkan menguji perilaku yang bisa diamati dari kode Anda, efek dari panggilan metode / fungsi pada status yang dapat diamati. Selama kode melakukan hal yang benar Anda baik-baik saja, Anda tidak perlu menguji apa pun.

Anda tidak perlu menyatakan secara eksplisit bahwa tipe enum memiliki entri yang Anda harapkan, sama seperti Anda tidak menyatakan secara eksplisit bahwa suatu kelas benar-benar ada atau bahwa ia memiliki metode dan atribut yang Anda harapkan.

Sebenarnya dengan menguji perilaku Anda secara implisit menyatakan bahwa kelas, metode, dan nilai yang terlibat dalam tes memang ada, sehingga Anda tidak perlu menyatakannya secara eksplisit.

Perhatikan bahwa Anda tidak perlu nama yang berarti untuk kode Anda untuk melakukan hal yang benar, itu hanya kenyamanan bagi orang yang membaca kode Anda. Anda dapat membuat kode Anda berfungsi dengan nilai enum seperti foo, bar... dan metode seperti frobnicate().

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.