หน่วยทดสอบหลายเงื่อนไขในคำสั่ง IF


26

ฉันมีโค้ดที่ดูเหมือนอะไรเช่นนี้:

function bool PassesBusinessRules()
{
    bool meetsBusinessRules = false;

    if (PassesBusinessRule1 
         && PassesBusinessRule2
         && PassesBusinessRule3)
    {
         meetsBusinessRules= true;
    }

    return meetsBusinessRules;
}

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

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

  • เท็จเท็จเท็จ
  • เท็จเท็จจริง
  • เท็จจริงเท็จ

และอื่น ๆ สำหรับแต่ละชุดค่าผสมที่เป็นไปได้

ฉันคิดว่ามันเกินความจริง แต่สมาชิกคนอื่น ๆ ในทีมของฉันทำไม่ได้ วิธีที่ฉันดูคือถ้า BusinessRule1 ล้มเหลวก็ควรกลับเท็จเสมอมันไม่สำคัญว่ามันจะถูกตรวจสอบครั้งแรกหรือครั้งสุดท้าย


คอมไพเลอร์ใช้การประเมินแบบโลภสำหรับตัวดำเนินการ && หรือไม่
suszterpatt

12
หากคุณเขียนการทดสอบ 10 บทคุณจะทำการทดสอบ && ไม่ใช่วิธีการของคุณ
Mert Akcakaya

2
จะมีเพียงแปดการทดสอบหากคุณทดสอบชุดค่าผสมที่เป็นไปได้ทั้งหมดหรือไม่ พารามิเตอร์บูลีนสามพารามิเตอร์เปิดหรือปิด
Kris Harper

3
@Mert: เฉพาะในกรณีที่คุณสามารถรับประกันได้ว่า && จะอยู่ที่นั่นเสมอ
Misko

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

คำตอบ:


29

อย่างเป็นทางการประเภทของความครอบคลุมเหล่านั้นมีชื่อ

ขั้นแรกให้มีการครอบคลุมภาคแสดง : คุณต้องการมีกรณีทดสอบที่ทำให้คำสั่ง if เป็นจริงและฉบับที่ทำให้เป็นเท็จ การได้รับความคุ้มครองนี้อาจเป็นความต้องการขั้นพื้นฐานสำหรับชุดทดสอบที่ดี

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

เกณฑ์ความครอบคลุมขั้นสูงสุดมักจะเรียกว่าCombinatorial Condition Coverage : ที่นี่มีเป้าหมายคือให้มีกรณีทดสอบที่ต้องผ่านค่าบูลีนที่เป็นไปได้ทั้งหมดในการทดสอบของคุณ

สิ่งนี้ดีกว่าเพรดิเคตหรือการครอบคลุมเงื่อนไขอย่างง่ายหรือไม่? ในแง่ของความคุ้มครองแน่นอน แต่มันไม่ฟรี มันมาพร้อมกับค่าใช้จ่ายที่สูงมากในการบำรุงรักษาทดสอบ ด้วยเหตุนี้คนส่วนใหญ่จึงไม่ต้องกังวลกับความคุ้มครอง combinatorial โดยปกติการทดสอบทุกสาขา (หรือทุกเงื่อนไข) จะดีพอสำหรับการจับข้อบกพร่อง การเพิ่มการทดสอบพิเศษสำหรับการทดสอบแบบ combinatorial มักจะไม่พบข้อบกพร่องมากขึ้น แต่ต้องใช้ความพยายามอย่างมากในการสร้างและบำรุงรักษา ความพยายามพิเศษมักจะทำให้สิ่งนี้ไม่คุ้มกับผลตอบแทนที่น้อยมากดังนั้นฉันจะไม่แนะนำสิ่งนี้

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


2
หากค่าบูลีนถูกส่งผ่านจากแหล่งภายนอก (หมายถึงค่าเหล่านั้นไม่ผ่านการตรวจสอบเสมอ) ดังนั้นการรายงานความครอบคลุมตามเงื่อนไขแบบ combinatorial มักจำเป็น ก่อนอื่นให้สร้างตารางของชุดค่าผสม จากนั้นสำหรับแต่ละรายการให้ตัดสินใจว่ารายการนั้นแสดงถึงกรณีการใช้งานที่มีความหมายหรือไม่ หากไม่มีควรมีรหัสบางส่วน (การยืนยันซอฟต์แวร์หรือส่วนการตรวจสอบความถูกต้อง) เพื่อป้องกันไม่ให้มีการใช้งานชุดค่าผสมนั้น เป็นสิ่งสำคัญที่จะไม่รวมพารามิเตอร์ทั้งหมดในการทดสอบ combinatorial: พยายามแบ่งพารามิเตอร์ออกเป็นกลุ่มที่มีปฏิสัมพันธ์ซึ่งกันและกันเช่นใช้การแสดงออกแบบบูลเดียวกัน

คุณมีคำที่เป็นตัวหนาเพียงใด ดูเหมือนว่าคำตอบของคุณจะเป็นเพียง "Combinatorial Condition Coverage" และทรัพยากรบางอย่างบอกว่า "predicate coverage" และ "conditional coverage" นั้นเป็นสิ่งเดียวกัน
Stijn

8

ในที่สุดมันก็ขึ้นอยู่กับคุณ (ทีม) รหัสและสภาพแวดล้อมของโครงการที่เฉพาะเจาะจง ไม่มีกฎสากล คุณ (ทีมงาน R) ควรเขียนการทดสอบมากที่สุดเท่าที่คุณจะต้องรู้สึกสะดวกสบายว่ารหัสที่ถูกต้องแน่นอน ดังนั้นหากเพื่อนร่วมทีมของคุณไม่มั่นใจในการทดสอบ 4 ครั้งคุณอาจต้องการมากกว่านี้

เวลา OTOH ในการเขียนการทดสอบหน่วยมักเป็นทรัพยากรที่หายาก ดังนั้นพยายามที่จะหาวิธีที่ดีที่สุดที่จะใช้เวลา จำกัด ที่คุณมี เช่นถ้าคุณมีวิธีการสำคัญอีกอย่างที่มีการครอบคลุม 0% มันอาจจะเป็นการดีกว่าถ้าคุณเขียนแบบทดสอบสองหน่วยเพื่อครอบคลุมวิธีนั้นแทนที่จะเพิ่มการทดสอบพิเศษสำหรับวิธีนี้ แน่นอนว่ามันยังขึ้นอยู่กับว่าการนำไปปฏิบัติของแต่ละคนนั้นมีความเปราะบางเพียงใด การวางแผนการเปลี่ยนแปลงวิธีนี้โดยเฉพาะอย่างยิ่งในอนาคตอันใกล้นี้อาจพิสูจน์ให้เห็นถึงการครอบคลุมการทดสอบหน่วยเพิ่มเติม ดังนั้นอาจเป็นเส้นทางที่สำคัญภายในโปรแกรม สิ่งเหล่านี้ล้วนเป็นปัจจัยที่มีเพียงคุณเท่านั้นที่สามารถประเมินได้

โดยส่วนตัวแล้วฉันมักจะมีความสุขกับการทดสอบ 4 แบบที่คุณเขียนนั่นคือ:

  • จริงเท็จเท็จ
  • เท็จจริงเท็จ
  • เท็จเท็จจริง
  • จริงจริงจริง

บวกหนึ่งอาจ:

  • จริงเท็จจริง

เพื่อให้แน่ใจว่าวิธีเดียวที่จะได้รับผลตอบแทนtrueคือการปฏิบัติตามกฎทางธุรกิจทั้ง 3 ข้อ แต่ในท้ายที่สุดถ้าเพื่อนร่วมทีมของคุณยืนยันว่ามีเส้นทาง combinatorial ที่ครอบคลุมมันอาจจะถูกกว่าที่จะเพิ่มการทดสอบพิเศษเหล่านั้นมากกว่าที่จะดำเนินการโต้แย้งต่อไปอีกนาน :-)


3

หากคุณต้องการความปลอดภัยคุณจะต้องทดสอบหน่วยแปดโดยใช้เงื่อนไขที่แสดงโดยตารางความจริงสามตัวแปร ( http://teach.valdosta.edu/plmoch/MATH4161/Spring%202004/and_or_if_files/image006.gif )

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


2
การทดสอบหน่วยคือการทดสอบกล่องสีขาว
PéterTörök

ลำดับที่ดีไม่ควรสำคัญ && สื่อสารได้หรืออย่างน้อยควรจะเป็น
Zachary K

2

ใช่ควรจะมีการผสมผสานอย่างเต็มรูปแบบในโลกอุดมคติ

เมื่อทำการทดสอบหน่วยคุณควรพยายามละเว้นวิธีการทำงานของมัน เพียงระบุอินพุต 3 รายการและตรวจสอบว่าเอาต์พุตถูกต้อง


1
การทดสอบหน่วยคือการทดสอบกล่องสีขาว และเราไม่ได้อาศัยอยู่ในโลกที่เหมาะ
PéterTörök

@ PéterTörök - เราไม่ได้อยู่ในโลกที่เหมาะที่จะให้แน่ใจว่า แต่stackexchangeไม่เห็นด้วยกับคุณในประเด็นอื่น ๆ โดยเฉพาะอย่างยิ่งสำหรับ TDD การทดสอบถูกเขียนไปยังข้อมูลจำเพาะไม่ใช่การดำเนินการ ฉันใช้ 'ข้อมูลจำเพาะ' เป็นการส่วนตัวเพื่อรวมอินพุตทั้งหมด (รวมถึงตัวแปรสมาชิก) และเอาท์พุททั้งหมด (รวมถึงผลข้างเคียง)
Telastyn

1
มันเป็นเพียงหนึ่งในหัวข้อที่เฉพาะเจาะจงใน StackOverflow, เกี่ยวกับกรณีที่เฉพาะเจาะจงซึ่งไม่ควร overgeneralized โดยเฉพาะอย่างยิ่งโพสต์ปัจจุบันนี้เห็นได้ชัดเกี่ยวกับการทดสอบรหัสที่เขียนแล้ว
PéterTörök

1

รัฐเป็นสิ่งชั่วร้าย ฟังก์ชั่นต่อไปนี้ไม่จำเป็นต้องมีการทดสอบหน่วยเพราะมันไม่มีผลข้างเคียงและเป็นที่เข้าใจกันดีว่ามันทำอะไรและไม่ทำอะไร ทำไมต้องทดสอบ คุณไม่เชื่อใจสมองของคุณเอง ??? ฟังก์ชั่นคงที่ยอดเยี่ยม!

static function bool Foo(bool a, bool b, bool c)
{
    return a && b && c;
}

2
ไม่ฉันไม่เชื่อใจในสมองของตัวเอง - ฉันเรียนรู้วิธีที่ยากลำบากในการตรวจสอบสิ่งที่ฉันทำอยู่เสมอ :-) ดังนั้นฉันจึงยังต้องการการทดสอบหน่วยเพื่อให้แน่ใจว่าฉันไม่ได้พิมพ์ผิดอะไรและไม่มีใครไป เพื่อทำลายรหัสในอนาคต และการทดสอบหน่วยมากขึ้นในการตรวจสอบวิธีการโทรที่ใช้คำนวณรัฐแทนด้วยa, และb cคุณสามารถย้ายตรรกะทางธุรกิจไปในทุกที่ที่คุณต้องการในท้ายที่สุดคุณยังต้องทดสอบที่ไหนสักแห่ง
PéterTörök

@ PéterTörökคุณยังสามารถพิมพ์ผิดในการทดสอบของคุณและจบลงด้วยการบวกเท็จดังนั้นคุณจะหยุดที่ไหน คุณเขียนการทดสอบหน่วยสำหรับการทดสอบหน่วยของคุณหรือไม่ ฉันไม่เชื่อใจสมองของฉัน 100% เช่นกัน แต่ในตอนท้ายของการเขียนรหัสคือสิ่งที่ฉันทำเพื่อหาเลี้ยงชีพ มีความเป็นไปได้ที่จะมีข้อผิดพลาดภายในฟังก์ชั่นนี้ แต่สิ่งสำคัญคือต้องเขียนโค้ดในลักษณะที่ข้อผิดพลาดจะง่ายต่อการติดตามไปยังแหล่งที่มาและเมื่อคุณแยกปัญหาและทำการแก้ไขคุณจะดีขึ้น . โค้ดที่เขียนได้ดีสามารถพึ่งพาการทดสอบการรวมส่วนใหญ่เป็นinfoq.com/presentations/Simple-Made-Easy
งาน

2
อันที่จริงการทดสอบอาจมีความผิดพลาดได้เช่นกัน (TDD ให้ความสำคัญกับเรื่องนี้โดยทำให้การทดสอบล้มเหลวก่อน) อย่างไรก็ตามการทำข้อผิดพลาดแบบเดียวกันสองครั้ง (และมองมัน) มีโอกาสน้อยกว่ามาก โดยทั่วไปแล้วการทดสอบจำนวนและชนิดไม่สามารถพิสูจน์ได้ว่าซอฟต์แวร์ปราศจากข้อบกพร่องเพียงลดความน่าจะเป็นของข้อบกพร่องให้อยู่ในระดับที่ยอมรับได้ และด้วยความเร็วของการติดตามบั๊กไปยังแหล่งที่มา IMO ไม่มีอะไรสามารถเอาชนะการทดสอบหน่วย - ข้อเสนอแนะที่รวดเร็ว rulez :-)
PéterTörök

"ฟังก์ชั่นต่อไปนี้ไม่จำเป็นต้องมีการทดสอบหน่วย" ฉันคิดว่าคุณกำลังประชดประชันที่นี่ แต่ก็ไม่ชัดเจน ฉันเชื่อใจในสมองของตัวเองหรือไม่? NO! ฉันเชื่อใจในสมองของคนต่อไปที่แตะต้องรหัสหรือไม่ ไม่ยิ่งกว่านั้นอีก! ฉันเชื่อว่าสมมติฐานทั้งหมดที่อยู่เบื้องหลังรหัสจะเป็นจริงหนึ่งปีนับจากนี้หรือไม่? ... คุณได้ดริฟท์ของฉัน นอกจากนี้ฟังก์ชั่นคงที่ฆ่า OO ... หากคุณต้องการทำ FP จากนั้นใช้ภาษา FP
Rob

1

ฉันรู้ว่าคำถามนี้ค่อนข้างเก่า แต่ฉันต้องการให้มุมมองที่แตกต่างกับปัญหา

ก่อนการทดสอบหน่วยของคุณควรมีวัตถุประสงค์สองประการ:

  1. สร้างเอกสารสำหรับคุณและเพื่อนร่วมทีมของคุณดังนั้นหลังจากเวลาที่กำหนดคุณสามารถอ่านการทดสอบหน่วยและทำให้แน่ใจว่าคุณเข้าใจwhat's the class' intentionและhow the class is doing its work
  2. ในขณะที่กำลังพัฒนาการทดสอบหน่วยทำให้แน่ใจว่ารหัสที่เราจดไว้กำลังทำงานอยู่ตามที่ตั้งใจไว้ในใจของเรา

ดังนั้นการสรุปปัญหาเราต้องการทดสอบ a complex if statementสำหรับตัวอย่างที่กำหนดมีความเป็นไปได้ 2 ^ 3 นั่นคือจำนวนการทดสอบที่สำคัญที่เราสามารถเขียนได้

  • คุณสามารถปรับให้เข้ากับข้อเท็จจริงนี้และเขียนการทดสอบ 8 ข้อหรือใช้ประโยชน์จากการทดสอบแบบพาราเมตริก
  • คุณยังสามารถทำตามคำตอบอื่น ๆ และจำไว้ว่าการทดสอบควรมีความชัดเจนด้วยความตั้งใจวิธีนี้เราจะไม่ไปยุ่งกับรายละเอียดมากเกินไปว่าในอนาคตอันใกล้นี้อาจทำให้ยากที่จะเข้าใจ what is doing the code

ในทางกลับกันถ้าคุณอยู่ในตำแหน่งที่การทดสอบของคุณซับซ้อนกว่าการนำไปใช้งานอาจเป็นเพราะการออกแบบควรนำไปใช้ใหม่ (มากหรือน้อยแล้วแต่กรณี) แทนที่จะทดสอบเอง

สำหรับคอมเพล็กซ์หากข้อความเช่นคุณอาจคิดถึงรูปแบบความรับผิดชอบต่อห่วงโซ่การใช้ตัวจัดการแต่ละตัวด้วยวิธีนี้:

If some simple business rule apply, derive to the next handler

จะง่ายเพียงใดในการทดสอบกฎง่ายๆหลายข้อแทนที่จะเป็นกฎที่ซับซ้อน

หวังว่ามันจะช่วย


0

นี่เป็นหนึ่งในกรณีที่มีสิ่งที่ชอบ quickcheck ( http://en.wikipedia.org/wiki/QuickCheck ) เป็นเพื่อนของคุณ แทนที่จะเขียนกรณี N ทั้งหมดด้วยมือให้คอมพิวเตอร์สร้างกรณีทดสอบที่เป็นไปได้ทั้งหมด (หรืออย่างน้อยจำนวนมาก) และตรวจสอบว่าทุกคนส่งคืนผลลัพธ์ที่สมเหตุสมผล

เราตั้งโปรแกรมคอมพิวเตอร์สำหรับการใช้ชีวิตที่นี่ทำไมไม่ตั้งโปรแกรมคอมพิวเตอร์เพื่อสร้างกรณีทดสอบสำหรับคุณ


0

คุณสามารถ refactor เงื่อนไขลงในเงื่อนไขยาม:

if (! PassesBusinessRule1) {
    return false;
}

if (! PassesBusinessRule2) {
    return false;
}

if (! PassesBusinessRule3) {
    return false;
}

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

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

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