มีจุดทดสอบหน่วยที่ stub และเยาะเย้ยทุกอย่างสาธารณะ?


58

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

การทดสอบหน่วยเป็นหัวข้อที่กว้างใหญ่และฉันรู้สึกว่าฉันเป็นคนที่ไม่เข้าใจอะไรบางอย่างที่นี่ อะไรคือข้อได้เปรียบที่สำคัญของการทดสอบหน่วยและการทดสอบการรวมระบบ (ไม่รวมค่าใช้จ่ายด้านเวลา)


4
สองเซ็นต์ของฉัน: อย่าใช้มากเกินไป mocks ( googletesting.blogspot.com/2013/05/…
Juan Mendes

คำตอบ:


37

เมื่อทำการทดสอบหน่วยวิธีที่ "เหมาะสม" คือการถูทุกสายสาธารณะและส่งกลับค่าที่กำหนดไว้ล่วงหน้าหรือ mocks ฉันรู้สึกว่าฉันไม่ได้ทดสอบอะไรเลย ฉันกำลังดูรหัสของฉันอย่างแท้จริงและสร้างตัวอย่างจากการไหลของตรรกะผ่านวิธีการสาธารณะของฉัน

ดูเหมือนว่าวิธีที่คุณกำลังทดสอบต้องการอินสแตนซ์ของคลาสอื่น ๆ (ซึ่งคุณต้องจำลอง) และเรียกใช้วิธีการต่าง ๆ ด้วยตนเอง

รหัสประเภทนี้ยากต่อการทดสอบหน่วยเนื่องจากเหตุผลที่คุณระบุ

สิ่งที่ฉันพบว่ามีประโยชน์คือการแบ่งชั้นเรียนออกเป็น:

  1. คลาสที่มี "ตรรกะทางธุรกิจ" จริง สิ่งเหล่านี้ใช้การเรียกคลาสน้อยหรือไม่มีเลยและง่ายต่อการทดสอบ (ค่า) ค่าออก
  2. คลาสที่อินเตอร์เฟสกับระบบภายนอก (ไฟล์ฐานข้อมูล ฯลฯ ) สิ่งเหล่านี้ล้อมรอบระบบภายนอกและจัดเตรียมอินเทอร์เฟซที่สะดวกสำหรับความต้องการของคุณ
  3. คลาสที่ "ผูกทุกอย่างเข้าด้วยกัน"

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

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


ตัวอย่าง

ชั้นหนึ่ง

สมมติว่าคุณมีคลาสที่ดึงราคาจากฐานข้อมูลนำส่วนลดมาใช้แล้วปรับปรุงฐานข้อมูล

หากคุณมีทั้งหมดนี้ในหนึ่งคลาสคุณจะต้องเรียกใช้ฟังก์ชัน DB ซึ่งยากต่อการเยาะเย้ย ใน pseudocode:

1 select price from database
2 perform price calculation, possibly fetching parameters from database
3 update price in database

ทั้งสามขั้นตอนจะต้องมีการเข้าถึงฐานข้อมูลดังนั้นการจำลอง (ซับซ้อน) จำนวนมากซึ่งมีแนวโน้มที่จะแตกถ้ารหัสหรือโครงสร้างฐานข้อมูลเปลี่ยนแปลง

แยกกัน

คุณแบ่งออกเป็นสามคลาส: การคำนวณราคา, PriceRepository, แอป

การคำนวณราคาจะทำการคำนวณตามจริงเท่านั้นและได้รับมูลค่าที่ต้องการ แอพเชื่อมโยงทุกอย่างเข้าด้วยกัน:

App:
fetch price data from PriceRepository
call PriceCalculation with input values
call PriceRepository to update prices

ทางนั้น:

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

ในที่สุดมันอาจกลายเป็นว่าการคำนวณราคาจะต้องทำการเรียกฐานข้อมูลของตัวเอง ตัวอย่างเช่นเนื่องจากการคำนวณราคาเท่านั้นที่ทราบถึงข้อมูลที่ต้องการดังนั้นจึงไม่สามารถเรียกข้อมูลล่วงหน้าได้โดยแอป จากนั้นคุณสามารถส่งต่อเป็นตัวอย่างของ PriceRepository (หรือคลาสที่เก็บข้อมูลอื่น) ที่ปรับแต่งตามความต้องการของ PriceCalculation ชั้นนี้แล้วจะต้องมีการเยาะเย้ย แต่นี้จะง่ายเพราะอินเตอร์เฟซ PriceRepository PriceRepository.getPrice(articleNo, contractType)เป็นเรื่องง่ายเช่น ที่สำคัญที่สุดอินเตอร์เฟสของ PriceRepository จะแยก PriceCalculation ออกจากฐานข้อมูลดังนั้นการเปลี่ยนแปลงใน DB schema หรือองค์กรข้อมูลจึงไม่น่าที่จะเปลี่ยนส่วนต่อประสานของมัน


5
ฉันคิดว่าฉันอยู่คนเดียวไม่เห็นจุดในการทดสอบหน่วยทุกอย่างขอบคุณ
enthrops

4
ฉันไม่เห็นด้วยเมื่อคุณบอกว่าคลาสของ type 3 มีน้อยฉันรู้สึกว่าส่วนใหญ่โค้ดของฉันคือ type 3 และแทบไม่มีตรรกะทางธุรกิจ นี่คือสิ่งที่ฉันหมายถึง: stackoverflow.com/questions/38496185/…
Rodrigo Ruiz

27

อะไรคือข้อดีของการทดสอบหน่วยและการทดสอบการรวมระบบ?

นั่นคือการแบ่งขั้วที่ผิดพลาด

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

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

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

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

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


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

หากคุณใช้เวลาส่วนใหญ่ในการเขียนบททดสอบสำหรับรหัสเรื่องเล็ก ๆ น้อย ๆ

public string SomeProperty { get; set; }

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

public string SomeMethod(string someProperty);

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


2
ฉันทราบว่าการทดสอบหน่วยและการทดสอบการรวมเซิร์ฟเวอร์เป้าหมายที่แตกต่างกันอย่างไรก็ตามฉันยังไม่ได้รับวิธีการทดสอบหน่วยที่มีประโยชน์ถ้าคุณ stub และเยาะเย้ยการโทรสาธารณะทั้งหมดที่การทดสอบหน่วยทำ ฉันจะเข้าใจ 'รหัสปฏิบัติตามสัญญาที่ระบุไว้โดยการทดสอบหน่วย' ถ้าไม่ใช่เพราะ stubs และ mocks; การทดสอบหน่วยของฉันเป็นการสะท้อนตรรกะอย่างแท้จริงภายในวิธีการที่ฉันทดสอบ คุณ (I) ไม่ได้ทำการทดสอบอะไรเลยเพียงแค่ดูที่รหัสของคุณและ 'แปลง' เป็นแบบทดสอบ เกี่ยวกับความยากในการใช้งานโดยอัตโนมัติและการครอบคลุมโค้ดตอนนี้ฉันกำลังทำงานกับ Rails และสิ่งเหล่านี้ได้รับการดูแลอย่างดี
enthrops

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

2
เหมาะสม แต่ก็ยังคงต้องทำให้การโทรสาธารณะอื่น ๆ ทั้งหมด (db, 'globals' บางอย่างเช่นสถานะผู้ใช้ปัจจุบัน ฯลฯ ) และจบลงด้วยการทดสอบโค้ดตามตรรกะวิธีการ
enthrops

1
ดังนั้นฉันจึงคิดว่าการทดสอบหน่วยสำหรับสิ่งที่แยกได้เป็นส่วนใหญ่ที่ยืนยันเป็น 'ชุดอินพุต -> ชุดของผลลัพธ์ที่คาดหวัง'
enthrops

1
ประสบการณ์ของฉันในการสร้างการทดสอบหน่วยและการรวมจำนวนมาก (ไม่พูดถึงการเยาะเย้ยขั้นสูงการทดสอบการรวมและเครื่องมือครอบคลุมรหัสที่ใช้โดยการทดสอบเหล่านั้น) ขัดแย้งกับข้อเรียกร้องส่วนใหญ่ของคุณที่นี่: 1) "จุดประสงค์ของการทดสอบหน่วย รหัสทำสิ่งที่ควรจะเป็น ": เหมือนกันกับการทดสอบการรวมระบบ (ยิ่งกว่านั้น); 2) "การทดสอบหน่วยตั้งค่าได้ง่ายกว่ามาก": ไม่พวกเขาไม่ได้ (มักจะเป็นการทดสอบการรวมที่ง่ายกว่า); 3) "เมื่อใช้อย่างถูกต้องการทดสอบหน่วยส่งเสริมการพัฒนา" แบบทดสอบ "รหัส": เหมือนกับการทดสอบการรวม; (ดำเนินการต่อ)
Rogério

4

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

คุณกำลังทดสอบพฤติกรรมของชั้นเรียนภายใต้การทดสอบไม่ใช่การใช้งาน หากคุณสร้างรหัสใหม่ (การสร้างวิธีการภายในใหม่ ฯลฯ ) การทดสอบหน่วยไม่ควรล้มเหลว แต่ถ้าคุณเปลี่ยนวิธีการสาธารณะทำอย่างนั้นการทดสอบควรล้มเหลวเพราะคุณเปลี่ยนพฤติกรรม

ดูเหมือนว่าคุณกำลังเขียนการทดสอบหลังจากที่คุณเขียนโค้ดแล้วลองเขียนการทดสอบแทนก่อน ลองสรุปพฤติกรรมที่คลาสควรมีแล้วเขียนจำนวนรหัสขั้นต่ำเพื่อให้การทดสอบผ่าน

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

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

UPDATE

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

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


และถ้าวิธีการใดไม่เรียกสิ่งใดว่าเป็นส่วนตัวแสดงว่าไม่มีประเด็นใดในการทดสอบหน่วยใช่ไหม
enthrops

หากวิธีนี้เป็นแบบส่วนตัวคุณไม่ต้องทดสอบอย่างชัดเจนควรทดสอบผ่านอินเทอร์เฟซสาธารณะ ควรทดสอบวิธีการสาธารณะทั้งหมดเพื่อให้แน่ใจว่าพฤติกรรมนั้นถูกต้อง
Schleis

ไม่ฉันหมายถึงว่าวิธีการสาธารณะไม่ได้เรียกสิ่งใดว่าเป็นส่วนตัวมันสมเหตุสมผลที่จะทดสอบวิธีการสาธารณะนั้นหรือไม่
enthrops

ใช่. วิธีการทำอะไรบางอย่างมันไม่ได้? ดังนั้นควรทดสอบ จากจุดทดสอบผมไม่รู้ว่ามันใช้อะไรเป็นส่วนตัวหรือเปล่า ฉันเพิ่งรู้ว่าถ้าฉันป้อนข้อมูล A ฉันควรได้ผลลัพธ์ B
Schleis

โอ้ใช่วิธีการทำบางสิ่งบางอย่างและสิ่งที่เรียกว่าวิธีการสาธารณะอื่น ๆ (และเฉพาะที่) วิธีที่คุณจะทดสอบอย่างถูกต้องนั่นคือการเรียกสายที่มีค่าส่งคืนแล้วตั้งค่าความคาดหวังของข้อความ คุณกำลังทดสอบอะไรในกรณีนี้ ว่าสายที่ถูกต้องจะทำอย่างไร คุณเขียนวิธีการนั้นและคุณสามารถดูและดูว่ามันทำอะไร ฉันคิดว่าการทดสอบหน่วยเหมาะกว่าสำหรับวิธีแยกที่ควรจะใช้เช่น 'อินพุต -> เอาท์พุท' ดังนั้นคุณสามารถตั้งค่าตัวอย่างจำนวนมากแล้วทำการทดสอบการถดถอยเมื่อคุณสร้างใหม่
enthrops

3

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

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

ที่จริงแล้วเยาะเย้ยมากเกินไปคือการต่อต้านรูปแบบ: TDD ต่อต้านรูปแบบและMocks เป็นความชั่วร้าย


0

แม้ว่า op ได้ทำเครื่องหมายคำตอบแล้ว แต่ฉันแค่เพิ่ม 2 เซ็นต์ของฉันที่นี่

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

และก็ในการตอบสนอง

เมื่อทำการทดสอบหน่วยวิธีที่ "เหมาะสม" คือการถูทุกสายสาธารณะและส่งกลับค่าที่กำหนดไว้ล่วงหน้าหรือ mocks ฉันรู้สึกว่าฉันไม่ได้ทดสอบอะไรเลย

มีประโยชน์ แต่ไม่ใช่สิ่งที่ OP ขอ:

การทดสอบหน่วยใช้งานได้ แต่ยังมีข้อบกพร่องอยู่หรือไม่

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

  1. อย่าสร้างการทดสอบหน่วยสำหรับวิธีส่วนตัว
  2. สร้างการทดสอบหน่วยสำหรับวิธีการส่วนตัว

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


พิจารณาคดีเมื่อวิธีส่วนตัวถูกนำกลับมาใช้โดยวิธีสาธารณะอื่น ๆ อีกมากมาย

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

หากฉันเลือกวิธีที่ 2: รหัสที่เขียนขึ้นสำหรับการทดสอบหน่วยจะค่อนข้างน้อยและจะทดสอบได้ง่ายกว่ามาก


พิจารณากรณีเมื่อไม่ใช้วิธีการส่วนตัวไม่มีวิธีการ ทดสอบหน่วยแยกต่างหากสำหรับวิธีการนั้น

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

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