มีค่าใดในการเขียนการทดสอบหน่วยที่เป็นส่วนย่อยของการทดสอบอื่นหรือไม่?


15

เพื่อให้เป็นตัวอย่างที่ได้รับการประดิษฐ์ขึ้นมาสมมติว่าฉันต้องการทดสอบว่าฟังก์ชันคืนค่าตัวเลขสองค่าและค่าแรกมีค่าน้อยกว่าค่าที่สอง:

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

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

ที่นี่ถ้าtest_lengthล้มเหลวก็test_orderจะล้มเหลวเช่นกัน มันเป็นวิธีปฏิบัติที่ดีที่สุดในการเขียนtest_lengthหรือข้ามมัน?

แก้ไข: โปรดทราบว่าในสถานการณ์นี้การทดสอบทั้งสองส่วนใหญ่เป็นอิสระจากกันการทดสอบแต่ละครั้งสามารถแยกออกจากกันหรืออาจทำงานในลำดับกลับกันสิ่งนี้ไม่สำคัญ ดังนั้นไม่มีคำถามเก่า ๆ เหล่านี้เลย

เป็นคู่ที่ซ้ำกันของข้างต้น



2
@ GlenH7 - ดูเหมือนคำถามอื่น อีกอย่างคือ "ถ้าคุณมีฟังก์ชั่นที่AโทรBและส่งกลับผลลัพธ์เดียวกันคุณควรทดสอบทั้งสองAและB" นี่เป็นเรื่องเกี่ยวกับการทดสอบที่ซ้อนทับมากกว่าฟังก์ชั่นที่อยู่ภายใต้การทดสอบ (แม้ว่าจะสับสนตามชื่อปัจจุบัน)
Telastyn


1
การพูดอย่างเข้มงวดในการทดสอบเหล่านี้จะไม่ทับซ้อนกันจริงๆ (พวกเขาไม่มีการพึ่งพาความสำเร็จ) ฟังก์ชั่นlambda: type('', (), {'__len__': lambda self: 2})()จะผ่านครั้งแรก แต่ไม่ใช่ครั้งที่สอง
liori

1
@ GlenH7: FWIW ฉันไม่ได้เปลี่ยนคำถามจริง ๆ เพียงแค่พยายามทำให้มันปลอดภัย - ;-) (@gnat: ไม่มีความผิดเพียงล้อเล่น!)
Doc Brown

คำตอบ:


28

อาจมีค่า แต่นี่เป็นกลิ่นเล็กน้อย ไม่ว่าการทดสอบของคุณจะไม่โดดเดี่ยว (เนื่องจากtest_orderทดสอบสองอย่างจริงๆ) หรือคุณมีความเชื่อในการทดสอบของคุณมากเกินไป

ในตัวอย่างฉันจะรวมการทดสอบทั้งสองเข้าด้วยกัน ใช่มันหมายความว่าคุณมีการยืนยันหลายครั้ง เลวร้ายเกินไป. คุณยังคงทดสอบสิ่งเดียว - ผลลัพธ์ของฟังก์ชัน บางครั้งในโลกแห่งความจริงนั่นหมายถึงการตรวจสอบสองครั้ง


ฉันยกระดับคำตอบของคุณแม้ว่ามันจะพลาดจุดหนึ่ง ใน Python การทดสอบครั้งที่สองจะล้มเหลวเมื่อmy_functionไม่ส่งคืนค่าสองค่าโดยไม่มีการยืนยันใด ๆ เนื่องจากการกำหนดจะส่งผลให้เกิดข้อยกเว้น ดังนั้นจึงไม่จำเป็นต้องใช้การยืนยันหลายชุดและการตรวจสอบสองครั้งเพื่อทดสอบสิ่งเดียวกัน
Doc Brown

@DocBrown - ฉันถือว่ามาก แต่ฉันไม่คุ้นเคยกับข้อความแสดงข้อผิดพลาดของ Python เพื่อทราบว่าอาจมีค่าในการยืนยันความล้มเหลวแทนข้อยกเว้น / ข้อผิดพลาดแบบสุ่มสำหรับเหตุผลที่ให้ข้อมูล
Telastyn

ฉันคิดว่าในสถานการณ์ปัจจุบันข้อความแสดงข้อผิดพลาดอาจมีข้อมูลเพียงพอ แต่โดยทั่วไปนั่นอาจไม่เป็นเช่นนั้น นั่นเป็นเหตุผลที่ฉันเห็นด้วยกับคุณว่าวิธีการทั่วไปสำหรับกรณีเช่นนี้ควรคิดถึง "การผสาน" โดยใช้การยืนยันสองชุด หากปรากฎว่าสามารถทำการทดสอบให้ง่ายขึ้นได้โดยออกจากการยืนยันข้อใดข้อหนึ่ง
Doc Brown

5
@DocBrown ค่าอื่น ๆ ในการตรวจสอบอย่างชัดเจนด้วยการยืนยันคือมันเป็นที่ชัดเจนสำหรับทุกคนที่ตรวจสอบการทดสอบว่านี่เป็นความล้มเหลวของรหัสภายใต้การทดสอบและไม่ได้ทดสอบตัวเอง เมื่อการทดสอบของฉันพบข้อยกเว้นที่ไม่คาดคิดฉันต้องใช้เวลาในการพิจารณาว่าข้อผิดพลาดจริง ๆ
Chris Hayes

@ChrisHayes: ฉันเขียนว่า "ไม่จำเป็นต้องมี" ไม่ใช่ "ไม่มีค่า"
Doc Brown

5

การทดสอบของคุณควรชัดเจน มันไม่ได้อนุมานอย่างสมบูรณ์ว่าถ้า text_length ล้มเหลว test_order ล้มเหลว

ฉันไม่แน่ใจว่ามันเป็นอย่างไรใน Python ที่คุณโพสต์ แต่ถ้าlen(result)เป็น 3 แล้วอันแรกจะล้มเหลว แต่อันที่สองอาจผ่าน (และถ้าไม่ใช่ใน Python ในภาษาเช่น JavaScript อย่างแน่นอน)

อย่างที่คุณพูดคุณต้องการทดสอบว่าฟังก์ชั่นคืนค่าสองตัวเลขและเป็นไปตามลำดับ การทดสอบสองแบบคือ


1
It's not completely inferred that if text_length fails test_order fails- ใน Python มันจะให้ข้อยกเว้นแก่คุณ
Doc Brown

ผมคิดว่าเป็นคำถามที่เกี่ยวกับกรณีที่ล้มเหลวของการแสดงถึงความล้มเหลวของtest_length test_orderความจริงที่ว่าการทดสอบคู่ที่คล้ายกันที่เขียนใน Javascript จะไม่ทำงานเหมือนกับการทดสอบแบบหลามสองแบบนี้ไม่เกี่ยวข้อง
Dawood พูดว่าคืนสถานะโมนิก้า

2
@DavidWallace: จำคำถามคือ "มันเป็นวิธีที่ดีที่สุดในการเขียน test_length หรือข้ามมัน"? ใน Javascript คุณต้องมีการทดสอบทั้งสองเพื่อให้แน่ใจว่าคุณจะไม่พลาดปัญหาใด ๆ (เมื่อคุณไม่รวมการทดสอบสองรายการเข้าด้วยกัน) ใน Python คุณสามารถละเว้นคำแรกได้อย่างปลอดภัย (ซึ่งถูกปฏิเสธในประโยคแรกของคำตอบนี้และประกาศเป็น "ฉันไม่แน่ใจ" ในวินาที) จริงๆแล้วคำตอบที่ดีนั้นต่างออกไป อย่างไรก็ตามฉันไม่ได้ลงคะแนนคำตอบนี้เพราะส่วนที่ดีคือการกล่าวถึง JavaScript
Doc Brown

4
@DavidWallace: เนื่องจากเราอยู่ที่นี่เป็น programmers.com ไม่ใช่ใน stackoverflow.com IMHO ที่ให้คำตอบซึ่งสามารถนำไปใช้กับภาษามากกว่าหนึ่งภาษานั้นดีกว่าคำตอบสำหรับภาษาเฉพาะเท่านั้น แต่เมื่อพูดถึงภาษาเฉพาะคำตอบควรถูกต้องเกี่ยวกับภาษาและไม่ผสมคุณสมบัติบางอย่าง
Doc Brown

1
สิ่งคือคำถามคือ "มันคุ้มค่าที่จะเขียนการทดสอบที่เป็นส่วนย่อยของการทดสอบอื่น" และคำตอบนี้บอกว่า "ในบางภาษาทั้งการทดสอบของคุณไม่เป็นส่วนย่อยของการทดสอบอื่น" แล้วถึงข้อสรุปการทดสอบทั้งสอง จึงจำเป็น มันอ่านให้ฉันราวกับว่ามีคนพูดว่า "โค้ดของคุณไม่ได้คอมไพล์เลยใน C ++ และนอกจากนี้ใน C ++ ฟังก์ชั่นสามารถคืนค่าได้หนึ่งค่าเท่านั้นดังนั้นคุณไม่จำเป็นต้องทดสอบมันคืนค่าที่สอง ;-)
Steve Jessop

2

คุณค่าเดียวของtest_lengthที่นี่คือถ้าทุกอย่างผ่านไปการมีอยู่ของมันบ่งบอกว่า "ความยาว" ได้รับการทดสอบแล้ว

ดังนั้นจึงไม่จำเป็นที่จะต้องทำการทดสอบทั้งสองนี้ เก็บไว้test_orderแต่พิจารณาเปลี่ยนชื่อtest_length_and_orderใหม่

บังเอิญฉันพบการใช้ชื่อที่ขึ้นต้นด้วยtestเงอะงะเล็กน้อย ฉันเป็นผู้สนับสนุนที่แข็งแกร่งของชื่อการทดสอบที่อธิบายถึงสภาพที่คุณยืนยัน


1
testหูดมีความหมายกับกรอบทดสอบ ธ ซึ่งแน่นอนว่าจำเป็นที่จะต้องไม่เปลี่ยนแปลงไม่ว่าคุณจะเป็นแฟนของมัน แต่ไม่เปลี่ยนน้ำหนักของอาร์กิวเมนต์ที่จำเป็นกับคนหยุดใช้มัน ;-)
สตีฟเจสซอพ

@ SteveJessop ใช่ฉันลืมไปว่ามันจำเป็น เมื่อผมเขียนหลามทดสอบในขณะที่ที่ผ่านมาผมได้เข้าไปในนิสัยของการเริ่มต้นพวกเขาทั้งหมดด้วยtest_that_เช่นtest_that_return_values_are_in_orderและอื่น ๆ บางทีเวอร์ชันกรอบการทดสอบในอนาคตจะสามารถแก้ไขข้อกำหนดนี้ได้
Dawood พูดว่าคืนสถานะโมนิก้า

@DavidWallace: คุณสามารถเปลี่ยนคำนำหน้าถ้าคุณต้องการ
โกหกไรอัน

1

ฉันจะแยกการทดสอบเหล่านี้ออกถ้านั่นคือสิ่งที่พวกเขาพัฒนาขึ้นมา ใช่test_orderมีแนวโน้มที่จะล้มเหลวเมื่อใดก็ตามที่test_lengthทำ แต่คุณรู้ว่าทำไมแน่นอน

ฉันยอมรับด้วยว่าหากการtest_orderปรากฏตัวครั้งแรกและคุณพบความล้มเหลวที่สามารถทดสอบได้คือผลลัพธ์อาจไม่ใช่สองค่าเพิ่มการตรวจสอบนั้นassertและเปลี่ยนชื่อการทดสอบเพื่อให้test_length_and_orderเหมาะสม

หากคุณต้องตรวจสอบประเภทของค่าที่ส่งคืนว่าเป็นจำนวนเต็มฉันจะรวมไว้ในการทดสอบผลลัพธ์ "รถโดยสาร" นี้

my_function()แต่ทราบตอนนี้คุณมีแบตเตอรี่ของการทดสอบผลของ หากมีหลายบริบท (หรือมากกว่ามีแนวโน้มที่หลายพารามิเตอร์) my_function()เพื่อทดสอบนี้ในขณะนี้สามารถย่อยเพื่อทดสอบผลทั้งหมดจาก

อย่างไรก็ตามเมื่อฉันเขียนการทดสอบหน่วยฉันมักจะทดสอบขอบและกรณีไม่ดีแยกจากอินพุตที่ดีและเอาต์พุตปกติ (ส่วนหนึ่งเป็นเพราะการทดสอบ "หน่วย" ส่วนใหญ่ของฉันมักจะเป็นการทดสอบแบบรวมขนาดเล็ก) และบ่อยครั้งที่มีการยืนยันหลายครั้ง เป็นการทดสอบแยกต่างหากหากพวกเขาล้มเหลวในวิธีการที่ฉันค้นหาฉันต้องการข้อมูลเพิ่มเติมโดยไม่ต้องดีบัก

ดังนั้นฉันอาจจะเริ่มต้นด้วยการทดสอบแยกต่างหากของคุณและขยายtest_lengthไปยังtest_length_and_typesและtest_orderแยกออกจากกันสมมติว่าหลังถูกมองว่าเป็น "การประมวลผลปกติ"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.