Apakah ada nilai dalam menulis tes unit yang merupakan bagian dari tes lain?

15

Untuk memberikan contoh yang sedikit dibuat-buat, katakanlah saya ingin menguji bahwa suatu fungsi mengembalikan dua angka, dan yang pertama lebih kecil dari yang kedua:

def test_length():
    result = my_function()
    assert len(result) == 2

def test_order()
    a, b = my_function()
    assert a < b

Di sini, jika test_lengthgagal, maka test_orderakan gagal juga. Apakah ini praktik terbaik untuk menulis test_length, atau melewatkannya?

EDIT: perhatikan bahwa dalam situasi ini, kedua tes sebagian besar independen satu sama lain, masing-masing dapat dijalankan secara terpisah, atau mereka dapat dijalankan dalam urutan terbalik, ini tidak masalah. Jadi tidak ada satu pun dari pertanyaan-pertanyaan ini sebelumnya

adalah duplikat dari yang di atas.

Mihai
sumber
2
@ GlenH7 - ini sepertinya pertanyaan yang berbeda. Yang lainnya adalah "jika Anda memiliki fungsi di mana Apanggilan Bdan mengembalikan hasil yang sama, haruskah Anda menguji keduanya Adan B". Ini lebih tentang tes yang tumpang tindih daripada fungsi yang diuji. (Meskipun itu membingungkan karena mereka saat ini dinamai).
Telastyn
1
Sebenarnya tes ini tidak benar-benar tumpang tindih (mereka tidak memiliki ketergantungan sukses). Suatu fungsi lambda: type('', (), {'__len__': lambda self: 2})()akan melewati yang pertama, tetapi bukan yang kedua.
liori
1
@ GlenH7: FWIW, saya tidak benar-benar mengubah pertanyaan, hanya mencoba membuatnya aman nyamuk ;-) (@gnat: jangan tersinggung, hanya bercanda!)
Doc Brown

Jawaban:

28

Mungkin ada nilai, tetapi ini sedikit bau. Entah tes Anda tidak terisolasi dengan baik (karena test_orderbenar-benar menguji dua hal) atau Anda terlalu dogmatis dalam pengujian Anda (membuat dua tes menguji hal logis yang sama).

Dalam contoh ini, saya akan menggabungkan dua tes bersama. Ya, itu berarti Anda memiliki beberapa penegasan. Sangat buruk. Anda masih menguji satu hal - hasil dari fungsi. Terkadang di dunia nyata itu berarti melakukan dua pemeriksaan.

Telastyn
sumber
Saya mengubah jawaban Anda meskipun itu meleset satu poin kecil. Dalam Python, tes kedua juga akan gagal ketika my_functiontidak mengembalikan tepat dua nilai, tanpa ada penegasan - karena tugas akan menghasilkan pengecualian. Jadi sebenarnya tidak perlu menggunakan beberapa konfirmasi dan dua cek untuk menguji hal yang sama.
Doc Brown
@DocBrown - Saya berasumsi banyak, tapi saya tidak terbiasa dengan pesan kesalahan Python untuk mengetahui apakah mungkin ada nilai dalam memiliki kegagalan, bukan pengecualian / kesalahan acak untuk alasan informatif.
Telastyn
Saya pikir dalam situasi saat ini pesan kesalahan mungkin cukup informatif. Tetapi secara umum, itu mungkin tidak terjadi. Itu sebabnya saya setuju dengan Anda bahwa pendekatan umum untuk kasus seperti ini adalah dengan memikirkan "penggabungan", menggunakan dua menegaskan. Jika ternyata tes dapat lebih disederhanakan dengan menyisihkan salah satu dari pernyataan tersebut, baiklah.
Doc Brown
5
@DocBrown Nilai lain dalam secara eksplisit memeriksa dengan tegas adalah bahwa menjadi jelas bagi siapa pun yang memeriksa tes bahwa ini adalah kegagalan kode yang diuji, dan bukan tes itu sendiri. Ketika tes saya menemukan pengecualian yang tidak terduga, saya selalu harus meluangkan waktu untuk mencari tahu mana yang sebenarnya salah.
Chris Hayes
@ ChrisHayes: Saya menulis "tidak perlu", tidak "tidak ada nilai" di dalamnya.
Doc Brown
5

Tes Anda harus eksplisit. Itu tidak sepenuhnya disimpulkan bahwa jika text_length gagal test_order gagal.

Saya tidak yakin bagaimana hasilnya dalam Python yang telah Anda posting, tetapi jika len(result)3 maka yang pertama akan gagal tetapi yang kedua mungkin lewat (dan jika tidak dalam Python, maka dalam bahasa seperti JavaScript pasti).

Seperti yang Anda katakan, Anda ingin menguji bahwa fungsi mengembalikan dua angka dan semuanya berurutan. Dua tes itu.

Hantu Madara
sumber
1
It's not completely inferred that if text_length fails test_order fails- dalam Python, itu, akan memberi Anda pengecualian.
Doc Brown
Saya pikir pertanyaannya adalah tentang kasus di mana kegagalan test_lengthmenyiratkan kegagalan test_order. Fakta bahwa sepasang tes serupa yang ditulis dalam Javascript tidak akan berperilaku sama dengan dua tes python ini agak tidak relevan.
Dawood mengatakan mengembalikan Monica
2
@ Davidvidallace: ingat, pertanyaannya adalah "Apakah ini praktik terbaik untuk menulis test_length, atau untuk melewatkannya"? Di Javascript, Anda perlu kedua pengujian untuk memastikan Anda tidak melewatkan masalah (saat Anda tidak menggabungkan kedua tes menjadi satu). Dengan Python, Anda dapat dengan aman menghilangkan yang pertama (yang ditolak pada kalimat pertama dari jawaban ini, dan dinyatakan sebagai "Saya tidak yakin" di yang kedua). Jujur, jawaban yang bagus terlihat berbeda. Namun, saya tidak downvote jawaban ini karena bagian yang baik sebenarnya adalah menyebutkan JavaScript.
Doc Brown
4
@ Davidvidallace: karena kita di sini adalah programmers.com, bukan pada stackoverflow.com, IMHO memberikan jawaban yang dapat diterapkan ke lebih dari satu bahasa lebih baik daripada jawaban hanya untuk bahasa tertentu. Tetapi ketika merujuk ke bahasa tertentu, jawabannya harus benar tentang bahasa tersebut, dan tidak mencampurkan beberapa properti.
Doc Brown
1
Masalahnya, pertanyaannya adalah "apakah itu layak untuk menulis tes yang merupakan bagian dari tes lain", dan jawaban ini mengatakan, "dalam beberapa bahasa, tak satu pun dari tes Anda adalah bagian dari yang lain" dan kemudian mencapai kesimpulan kedua tes oleh karena itu perlu. Bunyinya kepada saya seolah-olah seseorang berkata, "kode Anda tidak dikompilasi sama sekali dalam C ++, dan selain itu, dalam C ++ fungsi hanya dapat mengembalikan satu nilai sehingga Anda tidak perlu mengujinya mengembalikan dua. Hanya menulis satu tes" ;-)
Steve Jessop
2

Satu-satunya nilai di test_lengthsini adalah, jika semuanya lewat, keberadaannya menunjukkan bahwa "panjang" telah diuji.

Jadi kedua tes ini tidak perlu dilakukan. Simpan saja test_ordertetapi pertimbangkan untuk mengganti nama test_length_and_order.

Kebetulan, saya menemukan penggunaan nama yang dimulai dengan testsedikit canggung. Saya penganjur nama tes yang kuat yang benar-benar menggambarkan kondisi yang Anda nyatakan.

Dawood berkata mengembalikan Monica
sumber
1
The testkutil berarti bagi kerangka uji Python. Yang tentu saja tidak perlu mengubah apakah Anda penggemar, tetapi tidak mengubah bobot argumen yang diperlukan untuk menghentikan seseorang menggunakannya ;-)
Steve Jessop
@ SeveJessop Ya, saya terus lupa bahwa itu diperlukan. Ketika saya sedang menulis tes Python beberapa waktu lalu, saya terbiasa memulai semuanya dengan test_that_, seperti test_that_return_values_are_in_orderdan sebagainya. Mungkin versi masa depan kerangka uji akan mengatasi persyaratan ini entah bagaimana.
Dawood berkata mengembalikan Monica
@ Davidvidallace: Anda dapat mengubah awalan jika Anda mau.
Lie Ryan
1

Saya akan membiarkan tes-tes ini terpisah jika seperti itulah perkembangan mereka. Ya test_ordercenderung gagal kapan test_lengthsaja, tetapi Anda pasti tahu mengapa.

Saya juga setuju bahwa jika yang test_orderpertama muncul dan Anda menemukan kegagalan yang dapat diuji adalah bahwa hasilnya mungkin bukan dua nilai, menambahkan centang itu sebagai assertdan menamai ulang tes tersebut menjadi test_length_and_ordermasuk akal.

Jika Anda juga harus memeriksa jenis nilai yang dikembalikan adalah bilangan bulat, saya akan menyertakannya dalam tes hasil "omnibus" ini.

Tetapi perhatikan sekarang Anda memiliki baterai tes untuk hasilnya my_function(). Jika ada beberapa konteks (atau, lebih mungkin, beberapa parameter) untuk menguji ini sekarang dapat menjadi subrutin untuk menguji semua hasil my_function().

Namun, ketika saya menulis tes unit, saya biasanya menguji tepi dan kasus buruk secara terpisah dari input yang baik dan output normal (sebagian karena sebagian besar "unit" tes saya sering tes integrasi mini), dan sering dengan beberapa menegaskan, yang hanya rusak menjadi tes terpisah jika gagal dengan cara di mana saya menemukan saya ingin informasi lebih lanjut tanpa debugging.

Jadi saya mungkin akan mulai dengan tes terpisah Anda dan memperluas test_lengthke test_length_and_typesdan meninggalkan test_orderterpisah, dengan asumsi yang terakhir dianggap "pemrosesan normal".

Mark Hurd
sumber