การทดสอบการรวมหมายถึงการทดสอบหน่วยทั้งหมดซ้ำหรือไม่?


36

สมมติว่าฉันมีฟังก์ชั่น (เขียนใน Ruby แต่ทุกคนควรเข้าใจได้):

def am_I_old_enough?(name = 'filip')
   person = Person::API.new(name)
   if person.male?
      return person.age > 21
   else
      return person.age > 18
   end
end

ในการทดสอบหน่วยฉันจะสร้างการทดสอบสี่แบบเพื่อให้ครอบคลุมทุกสถานการณ์ แต่ละคนจะใช้ล้อเลียนPerson::APIวัตถุที่มีวิธีการที่ค้างอยู่และmale?age

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

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


3
หนึ่งในประเด็นคือว่าโดยการเยาะเย้ย / ทดสอบหน่วยคุณสามารถแยกปัญหาใด ๆ กับรหัสของคุณ หากการทดสอบการรวมล้มเหลวคุณจะไม่ทราบว่ารหัสใดที่ใช้งานไม่ได้คุณหรือ API
Chris Wohlert

9
ทดสอบสี่เท่านั้น? คุณมีขอบเขตอายุหกขวบที่คุณควรทำการทดสอบ: 17, 18, 19, 20, 21, 22 ... ;)
David Arno

22
@FilipBartuzi ฉันคิดว่าวิธีการตรวจสอบว่าเพศชายมากกว่า 21 หรือไม่? ตามที่เขียนไว้ในปัจจุบันมันไม่ได้ทำเช่นนั้นมันจะเป็นจริงได้ก็ต่อเมื่อพวกเขามีอายุ 22 ปีขึ้นไป "มากกว่า 21" ในภาษาอังกฤษ แต่หมายถึง "21+" ดังนั้นจึงมีข้อผิดพลาดในรหัสของคุณ ข้อบกพร่องดังกล่าวจะถูกจับโดยการทดสอบค่าขอบเขตเช่น 20, 21, 22 สำหรับผู้ชาย, 17,18,19 สำหรับผู้หญิงในกรณีนี้ ดังนั้นต้องมีการทดสอบอย่างน้อยหกครั้ง
David Arno

6
ไม่พูดถึงกรณีของ 0 และ -1 บุคคลอายุ 1 ปีหมายความว่าอย่างไร รหัสของคุณควรทำอย่างไรถ้า API ของคุณส่งคืนสิ่งที่ไร้สาระ?
RubberDuck

9
นี่จะเป็นการง่ายกว่ามากในการทดสอบว่าคุณผ่านวัตถุบุคคลเป็นพารามิเตอร์
JeffO

คำตอบ:


72

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

จุดของการทดสอบหน่วยคือเพื่อให้แน่ใจว่าฟังก์ชั่นเล็ก ๆ น้อย ๆ ที่เฉพาะเจาะจงทำงานอย่างถูกต้องและสมบูรณ์ตามที่ตั้งใจไว้ การทดสอบหน่วยam_i_old_enoughจะทดสอบข้อมูลที่มีทุกเพศทุกวัยที่แตกต่างกันอย่างแน่นอนคนที่อยู่ใกล้กับเกณฑ์ที่อาจเป็นไปได้ทั้งหมดที่เกิดขึ้นในทุกเพศทุกวัยของมนุษย์ หลังจากที่คุณเขียนแบบทดสอบนี้แล้วความสมบูรณ์ของam_i_old_enoughไม่ควรเป็นปัญหาอีกต่อไป

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

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

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


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

1
JB Rainsberger มีการพูดคุยที่ดีเกี่ยวกับการทดสอบและการระเบิด combinatorial คุณเขียนกำลังในย่อหน้าสุดท้ายที่เรียกว่า"การทดสอบแบบบูรณาการเป็นหลอกลวง" มันไม่ได้เกี่ยวกับการทดสอบการรวมระบบ แต่ยังน่าสนใจทีเดียว
Bart van Nierop

The customer doesn't care about a particular utility function you wrote, they care that their web app is properly secured against access by minors-> นั่นคือความคิดที่ฉลาดมากขอบคุณ! ปัญหาคือเมื่อคุณทำโครงการด้วยตัวคุณเอง มันยากที่จะแยกความคิดของคุณระหว่างการเป็นโปรแกรมเมอร์และเป็นผู้จัดการผลิตภัณฑ์ในขณะเดียวกัน
ฆา Bartuzi

14

คำตอบสั้น ๆ คือ "ไม่" ส่วนที่น่าสนใจมากขึ้นคือสาเหตุ / วิธีสถานการณ์นี้อาจเกิดขึ้น

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

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

เหตุผลที่ชัดเจนที่สุดคือฟังก์ชั่นของคุณกำลังทำงานสองอย่างที่แตกต่างกัน:

  • มองPersonตามชื่อของพวกเขา ต้องมีการทดสอบการรวมเพื่อให้แน่ใจว่าสามารถค้นหาPersonวัตถุที่ถูกสร้างขึ้น / เก็บไว้ที่อื่น
  • การคำนวณว่า a Personเก่าพอหรือไม่ขึ้นอยู่กับเพศของพวกเขา ต้องมีการทดสอบหน่วยเพื่อให้แน่ใจว่าการคำนวณมีประสิทธิภาพตามที่คาดไว้

โดยการจัดกลุ่มงานเหล่านี้เข้าด้วยกันเป็นหนึ่งบล็อคโค้ดคุณจะไม่สามารถเรียกใช้งานได้หากไม่มีงานอื่น เมื่อคุณต้องการทดสอบหน่วยการคำนวณคุณจะถูกบังคับให้ค้นหา a Person(จากฐานข้อมูลจริงหรือจาก stub / mock) เมื่อคุณต้องการทดสอบว่าการค้นหาผสานกับส่วนที่เหลือของระบบคุณจะถูกบังคับให้ทำการคำนวณตามอายุด้วย เราควรทำอย่างไรกับการคำนวณนั้น? เราควรเพิกเฉยหรือตรวจสอบหรือไม่ ดูเหมือนจะเป็นสถานการณ์ที่แน่นอนที่คุณอธิบายในคำถามของคุณ

หากเราจินตนาการถึงทางเลือกเราอาจมีการคำนวณด้วยตัวเอง:

def is_old_enough?(person)
   if person.male?
      return person.age > 21
   else 
      return person.age > 18
   end
end

เนื่องจากนี่เป็นการคำนวณที่บริสุทธิ์เราจึงไม่จำเป็นต้องทำการทดสอบการรวมเข้าด้วยกัน

เราอาจถูกล่อลวงให้เขียนงานค้นหาแยกต่างหากเช่นกัน:

def person_from_name(name = 'filip')
   return Person::API.new(name)
end

อย่างไรก็ตามในกรณีนี้ฟังก์ชั่นอยู่ใกล้กับPerson::API.newที่ฉันบอกว่าคุณควรจะใช้มันแทน (หากจำเป็นต้องใช้ชื่อเริ่มต้นมันจะถูกเก็บไว้ที่อื่นดีกว่าเช่นแอตทริบิวต์ class หรือไม่)

เมื่อเขียนการทดสอบการรวมสำหรับPerson::API.new(หรือperson_from_name) สิ่งที่คุณต้องใส่ใจคือว่าคุณได้รับสิ่งที่คาดหวังกลับมาPersonหรือไม่ การคำนวณตามอายุทั้งหมดได้รับการดูแลจากที่อื่นดังนั้นการทดสอบการรวมกลุ่มของคุณจึงไม่สนใจ


11

อีกจุดหนึ่งที่ฉันต้องการเพิ่มในคำตอบของ Killianคือการทดสอบหน่วยทำงานอย่างรวดเร็วดังนั้นเราจึงสามารถทดสอบได้ 1,000 ข้อ โดยทั่วไปแล้วการทดสอบการรวมจะใช้เวลานานกว่าเนื่องจากกำลังเรียกบริการเว็บฐานข้อมูลหรือการพึ่งพาจากภายนอกอื่น ๆ ดังนั้นเราจึงไม่สามารถทำการทดสอบแบบเดียวกัน (1,000 ครั้ง) สำหรับสถานการณ์การรวมระบบเนื่องจากต้องใช้เวลามากเกินไป

นอกจากนี้โดยทั่วไปแล้วการทดสอบหน่วยจะได้รับการรันในเวลาบิลด์ (บนเครื่องสร้าง) และการทดสอบการรวมจะทำงานหลังจากการปรับใช้กับสภาพแวดล้อม / เครื่อง

โดยทั่วไปแล้วจะเรียกใช้การทดสอบหน่วย 1,000 ครั้งของเราสำหรับทุกบิลด์จากนั้นทดสอบการผสานรวม 100 ค่าหรือสูงกว่าหลังจากการปรับใช้ทุกครั้ง เราอาจไม่ใช้แต่ละบิลด์เพื่อปรับใช้ แต่ก็ใช้ได้เพราะบิลด์ที่เราใช้ในการปรับใช้นั้นการทดสอบการรวมจะถูกเรียกใช้ โดยทั่วไปเราต้องการ จำกัด การทดสอบเหล่านี้ให้ทำงานภายใน 10 หรือ 15 นาทีเพราะเราไม่ต้องการให้การปรับใช้นานเกินไป

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


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