ฉันเข้าใจการพัฒนาโดยใช้การทดสอบจนคุณได้รับอนุญาตให้เขียนโค้ดที่มีประสิทธิผลเมื่อคุณมีการทดสอบหน่วยที่ล้มเหลว (สีแดง) จากนี้ฉันมีคำถามว่าวิธีการทดสอบที่ขับเคลื่อนด้วยสามารถนำไปใช้กับการทดสอบรูปแบบอื่น ๆ
ฉันเข้าใจการพัฒนาโดยใช้การทดสอบจนคุณได้รับอนุญาตให้เขียนโค้ดที่มีประสิทธิผลเมื่อคุณมีการทดสอบหน่วยที่ล้มเหลว (สีแดง) จากนี้ฉันมีคำถามว่าวิธีการทดสอบที่ขับเคลื่อนด้วยสามารถนำไปใช้กับการทดสอบรูปแบบอื่น ๆ
คำตอบ:
TDD ทั้งหมดที่คุณต้องการคือการที่คุณเขียนการทดสอบที่ล้มเหลวจากนั้นปรับเปลี่ยนรหัสของคุณเพื่อให้ผ่าน
โดยทั่วไป "การทดสอบหน่วย" มีขนาดเล็กและรวดเร็วและทดสอบบางส่วนของรหัสของคุณในการแยก เพราะมันเร็วจึงทำให้เรด / เขียว / รีแฟคเตอร์เร็วเกินไป อย่างไรก็ตามพวกเขาประสบเฉพาะการทดสอบชิ้นส่วนในการแยก ดังนั้นคุณต้องมีการทดสอบอื่น ๆ ด้วย (การรวมการยอมรับ ฯลฯ ) ยังคงเป็นวิธีปฏิบัติที่ดีในการปฏิบัติตามหลักการเดียวกัน: เขียนการทดสอบที่ล้มเหลวจากนั้นปรับเปลี่ยนรหัสเพื่อให้ทำงานได้ เพิ่งทราบว่าโดยทั่วไปแล้วจะช้าลงดังนั้นจึงสามารถส่งผลต่อรอบเวลาสีแดง / เขียว / refactor
วงจร refactor สีเขียวสีแดงสร้างขึ้นบนหลักการที่ดีมากหนึ่งเสียง:
เชื่อถือเฉพาะการทดสอบที่คุณเห็นทั้งผ่านและไม่ผ่าน
ใช่ใช้งานได้กับการทดสอบการรวมอัตโนมัติ ทดสอบด้วยตนเอง เฮคใช้งานได้กับเครื่องทดสอบแบตเตอรี่รถยนต์ นี่คือวิธีทดสอบการทดสอบ
บางคนคิดว่าการทดสอบหน่วยครอบคลุมสิ่งที่เล็กที่สุดที่สามารถทดสอบได้ บางคนคิดว่าอะไรที่ทดสอบได้เร็ว TDD เป็นมากกว่าวงจรการรีแฟคเตอร์สีเขียวสีแดง แต่ส่วนนั้นมีชุดการทดสอบที่เฉพาะเจาะจงมาก: ไม่ใช่การทดสอบที่คุณจะต้องวิ่งหนึ่งครั้งก่อนส่งการเปลี่ยนแปลง เป็นการทดสอบที่คุณจะเรียกใช้ทุกครั้งที่คุณทำการเปลี่ยนแปลงใด ๆ สำหรับฉันแล้วนั่นคือการทดสอบหน่วยของคุณ
อย่างไรก็ตามฉันสงสัยว่าวิธีทดสอบด้วยการทดสอบนั้นสามารถนำไปใช้กับการทดสอบรูปแบบอื่นได้หรือไม่
ใช่และเป็นวิธีที่รู้จักกันดีซึ่งก็คือการพัฒนาพฤติกรรมที่ขับเคลื่อนด้วย การทดสอบที่สร้างขึ้นจากสเป็คอย่างเป็นทางการใน BDD อาจเรียกว่า "การทดสอบหน่วย" แต่โดยทั่วไปจะไม่ได้ระดับต่ำเช่นเดียวกับ TDD จริงพวกเขาอาจจะดีกว่าคำว่า "การทดสอบการยอมรับ"
ฉันเข้าใจการพัฒนาโดยใช้การทดสอบจนคุณได้รับอนุญาตให้เขียนโค้ดที่มีประสิทธิผลเมื่อคุณมีการทดสอบหน่วยที่ล้มเหลว (สีแดง)
ไม่ได้คุณได้รับอนุญาตให้เขียนรหัสที่ง่ายที่สุดเท่าที่จะทำได้เพื่อเปลี่ยนข้อความของการทดสอบ มันไม่ได้พูดอะไรเกี่ยวกับการทดสอบแบบไหน
ในความเป็นจริงคุณอาจเริ่มต้นด้วยการเขียนการทดสอบการยอมรับ (สีแดง) สำหรับเกณฑ์การยอมรับอย่างแม่นยำยิ่งขึ้นคุณเขียนการทดสอบการยอมรับที่ง่ายที่สุดที่อาจล้มเหลว หลังจากนั้นคุณรันการทดสอบดูว่ามันล้มเหลวและตรวจสอบว่ามันล้มเหลวด้วยเหตุผลที่ถูกต้อง จากนั้นคุณเขียนการทดสอบการทำงานที่ล้มเหลวสำหรับชิ้นส่วนการทำงานของเกณฑ์การยอมรับนั้นอีกครั้งคุณเขียนการทดสอบการทำงานที่ง่ายที่สุดที่อาจล้มเหลวรันรันดูมันล้มเหลวและตรวจสอบว่าล้มเหลวด้วยเหตุผลที่เหมาะสม จากนั้นคุณเขียนการทดสอบหน่วยที่ล้มเหลวการทดสอบหน่วยที่ง่ายที่สุดที่อาจล้มเหลวรันมันดูมันล้มเหลวตรวจสอบว่ามันล้มเหลวด้วยเหตุผลที่ถูกต้อง
ตอนนี้คุณเขียนรหัสการผลิตที่ง่ายที่สุดที่อาจเปลี่ยนข้อความแสดงข้อผิดพลาด เรียกใช้การทดสอบอีกครั้งตรวจสอบว่ามีการเปลี่ยนแปลงข้อความแสดงข้อผิดพลาดเปลี่ยนไปในทิศทางที่ถูกต้องและรหัสเปลี่ยนข้อความด้วยเหตุผลที่ถูกต้อง (เป็นการดีที่ข้อความข้อผิดพลาดควรจะผ่านไปแล้วและการทดสอบควรผ่าน แต่บ่อยครั้งกว่าจะดีกว่าที่จะทำตามขั้นตอนเล็ก ๆ เปลี่ยนข้อความแทนที่จะพยายามให้การทดสอบผ่านในครั้งเดียว - นั่นคือเหตุผล ทำไมนักพัฒนากรอบการทดสอบใช้ความพยายามอย่างมากกับข้อความแสดงข้อผิดพลาด!)
เมื่อคุณได้รับการทดสอบหน่วยผ่านคุณ refactor รหัสการผลิตของคุณภายใต้การคุ้มครองของการทดสอบของคุณ (โปรดทราบว่าในเวลานี้การทดสอบการยอมรับและการทดสอบการทำงานยังคงล้มเหลว แต่ก็ไม่เป็นไรเนื่องจากคุณเป็นเพียงการปรับโครงสร้างหน่วยแต่ละหน่วยที่ครอบคลุมโดยการทดสอบหน่วย)
ตอนนี้คุณสร้างการทดสอบหน่วยถัดไปและทำซ้ำข้างต้นจนกว่าการทดสอบการทำงานจะผ่าน ภายใต้การคุ้มครองการทดสอบการทำงานตอนนี้คุณสามารถทำการปรับโครงสร้างซ้ำในหลาย ๆ หน่วยได้แล้ว
รอบกลางนี้จะทำซ้ำจนกว่าการทดสอบการยอมรับจะผ่านไป ณ จุดที่คุณสามารถทำการปรับโครงสร้างใหม่ในทั้งระบบได้
ตอนนี้คุณเลือกเกณฑ์การยอมรับถัดไปและวัฏจักรรอบนอกเริ่มต้นอีกครั้ง
Kent Beck ผู้ค้นพบ TDD (เขาไม่ชอบคำว่า "ผู้ประดิษฐ์" เขาบอกว่าผู้คนทำสิ่งนี้มาตลอดเขาแค่ตั้งชื่อและเขียนหนังสือเกี่ยวกับมัน) ใช้การเปรียบเทียบจากการถ่ายภาพและ เรียกสิ่งนี้ว่า "การซูมเข้าและออก"
หมายเหตุ: คุณไม่จำเป็นต้องทำการทดสอบสามระดับเสมอไป บางทีบางครั้งคุณก็ต้องการมากกว่านี้ บ่อยขึ้นคุณต้องการน้อยลง หากฟังก์ชันการทำงานของคุณมีขนาดเล็กและการทดสอบการทำงานของคุณนั้นรวดเร็วคุณสามารถทำได้โดยไม่ต้อง (หรือมีการทดสอบหน่วยน้อยกว่า) บ่อยครั้งที่คุณต้องทดสอบการยอมรับและการทดสอบหน่วย หรือเกณฑ์การยอมรับของคุณนั้นละเอียดมากจนการทดสอบการยอมรับของคุณเป็นการทดสอบที่ใช้งานได้
Kent Beck กล่าวว่าถ้าเขามีการทดสอบการทำงานที่รวดเร็วขนาดเล็กและมุ่งเน้นเขาจะเขียนการทดสอบหน่วยก่อนปล่อยให้การทดสอบหน่วยขับรหัสแล้วลบ (บางส่วน) การทดสอบหน่วยอีกครั้งที่ครอบคลุมรหัสที่ยัง ครอบคลุมโดยการทดสอบการทำงานที่รวดเร็ว ข้อควรจำ: รหัสทดสอบเป็นรหัสที่ต้องบำรุงรักษาและปรับโครงสร้างใหม่ให้น้อยยิ่งดี!
อย่างไรก็ตามฉันสงสัยว่าวิธีทดสอบด้วยการทดสอบนั้นสามารถนำไปใช้กับการทดสอบรูปแบบอื่นได้หรือไม่
คุณไม่ได้ใช้ TDD กับการทดสอบจริงๆ คุณใช้กับกระบวนการพัฒนาทั้งหมดของคุณ นั่นคือสิ่งที่ "ขับเคลื่อน" ส่วนหนึ่งของการทดสอบ - ขับเคลื่อน - การพัฒนาหมายถึง: การพัฒนาทั้งหมดของคุณถูกขับเคลื่อนด้วยการทดสอบ การทดสอบไม่เพียง แต่ขับรหัสที่คุณเขียนเท่านั้น แต่ยังทดสอบไดรฟ์ที่จะเขียนรหัสซึ่งต้องเขียนรหัสถัดไป พวกเขาผลักดันการออกแบบของคุณ พวกเขาบอกคุณเมื่อคุณทำ พวกเขาบอกคุณว่าจะทำงานต่อไป พวกเขาบอกคุณเกี่ยวกับข้อบกพร่องในการออกแบบในรหัสของคุณ (เมื่อการทดสอบยากที่จะเขียน)
คี ธ Braithwaite ได้สร้างการออกกำลังกายที่เขาเรียกว่าTDD เช่นถ้าคุณหมายถึงมัน ประกอบด้วยชุดของกฎ (ตามกฎสามข้อของ TDD ของลุงมาร์ตินแต่เข้มงวดกว่า) ที่คุณต้องปฏิบัติตามอย่างเคร่งครัดและได้รับการออกแบบมาเพื่อนำคุณไปสู่การใช้ TDD อย่างเข้มงวดยิ่งขึ้น มันทำงานได้ดีที่สุดกับการเขียนโปรแกรมคู่ (เพื่อให้คู่ของคุณสามารถตรวจสอบให้แน่ใจว่าคุณไม่ได้ละเมิดกฎ) และผู้สอน
กฎคือ:
- เขียนการทดสอบใหม่หนึ่งการทดสอบที่เล็กที่สุดที่คุณสามารถชี้ไปในทิศทางของโซลูชันได้
- เห็นมันล้มเหลว การรวบรวมความล้มเหลวนับเป็นความล้มเหลว
- ทำให้การทดสอบจาก (1) การส่งผ่านโดยการเขียนรหัสการดำเนินการอย่างน้อยคุณสามารถในวิธีการทดสอบ
- Refactor เพื่อลบการทำซ้ำและอื่น ๆ ตามที่จำเป็นในการปรับปรุงการออกแบบ เข้มงวดเกี่ยวกับการใช้ท่าเหล่านี้:
- คุณต้องการวิธีการใหม่ - รอจนกว่าจะถึงเวลาการทำให้ใหม่แล้ว ...สร้างวิธีการใหม่ (ไม่ใช่การทดสอบ) โดยทำอย่างใดอย่างหนึ่งต่อไปนี้และไม่ใช้วิธีอื่น:
- ที่ต้องการ: ทำวิธีการแยกในรหัสการใช้งานที่สร้างขึ้นตาม (3) เพื่อสร้างวิธีการใหม่ในชั้นเรียนทดสอบหรือ
- หากคุณต้อง: ย้ายรหัสการใช้งานตาม (3) ไปยังวิธีการใช้งานที่มีอยู่
- คุณต้องการคลาสใหม่ - รอจนกว่าจะถึงเวลารีแฟคเจอริ่งแล้ว ...สร้างคลาสที่ไม่ได้ทดสอบเพื่อระบุปลายทางสำหรับวิธีการย้ายและไม่มีเหตุผลอื่น
- เติมคลาสการใช้งานด้วยวิธีการโดยใช้วิธีการย้ายและไม่มีวิธีอื่น
กฎเหล่านี้มีไว้สำหรับการออกกำลังกาย TDD พวกเขาไม่ได้มีไว้สำหรับการทำ TDD จริง ๆ (แม้ว่าจะไม่มีอะไรขัดขวางคุณจากการทดลองใช้) พวกเขาสามารถรู้สึกหงุดหงิดเพราะบางครั้งมันจะดูเหมือนว่าคุณทำตามขั้นตอนเล็ก ๆ น้อย ๆ เป็นพัน ๆ โดยไม่ทำอะไรเลย
TDD ไม่ได้ จำกัด อยู่ที่ชุมชนการทดสอบซอฟต์แวร์แบบดั้งเดิมเรียกว่า "การทดสอบหน่วย" ความเข้าใจผิดที่เกิดขึ้นบ่อยครั้งนี้เป็นผลมาจากคำว่า "หน่วย" ที่เกินความโชคร้ายของ Kent Beck เมื่ออธิบายการฝึกฝน TDD ของเขา สิ่งที่เขาหมายถึงโดย "การทดสอบหน่วย" คือการทดสอบที่ทำงานแยก มันไม่ได้ขึ้นอยู่กับการทดสอบอื่น ๆ การทดสอบแต่ละครั้งจะต้องตั้งค่าสถานะที่ต้องการและทำการล้างข้อมูลใด ๆ เมื่อเสร็จสิ้น ในแง่นี้การทดสอบหน่วยในความหมาย TDD เป็นหน่วย มันมีอยู่ในตัวเอง มันสามารถทำงานได้ด้วยตัวเองหรือสามารถทำงานพร้อมกับการทดสอบหน่วยอื่น ๆ ในลำดับใด ๆ
การอ้างอิง : "การทดสอบการพัฒนาขับเคลื่อนด้วยตัวอย่าง" โดย Kent Beck
Kent Beck อธิบายถึงความหมายของ“ การทดสอบหน่วย” ในบทที่ 32 - การควบคุม TDD
ฉันยังไม่ได้อ่านหนังสือและไม่ได้ปฏิบัติตามมาตรฐาน TDD ตลอดเวลา แต่ในใจของฉันประเด็นหลักของปรัชญา TDD ที่ฉันเห็นด้วยคือคุณต้องกำหนดความสำเร็จก่อน . สิ่งนี้มีความสำคัญในทุกระดับของการออกแบบจาก "เป้าหมายของโครงการนี้คืออะไร" ถึง "สิ่งที่อินพุตและเอาต์พุตของวิธีการขนาดเล็กนี้ควรเป็นอย่างไร"
มีหลายวิธีในการทำคำจำกัดความของความสำเร็จนี้ วิธีหนึ่งที่มีประโยชน์โดยเฉพาะอย่างยิ่งสำหรับวิธีการระดับต่ำที่มีกรณีขอบจำนวนมากอาจเป็นการทดสอบการเขียนในรหัส สำหรับบางระดับของนามธรรมมันจะมีประโยชน์เพียงแค่จดบันทึกย่อเกี่ยวกับเป้าหมายของโมดูลหรืออะไรก็ตามหรือแม้แต่ตรวจสอบจิตใจด้วยตนเอง (หรือขอให้เพื่อนร่วมงาน) ตรวจสอบให้แน่ใจว่าทุกอย่างสมเหตุสมผลและอยู่ใน สถานที่ตรรกะ บางครั้งการอธิบายการทดสอบการรวมเข้าด้วยกันในรหัส (และแน่นอนว่าจะช่วยให้การทดสอบเป็นไปโดยอัตโนมัติ) และบางครั้งก็มีประโยชน์ในการกำหนดแผนการทดสอบอย่างรวดเร็วที่สมเหตุสมผลคุณสามารถใช้เพื่อให้แน่ใจว่าระบบทั้งหมดทำงานร่วมกันในแบบของคุณ คาดหวัง
แต่ไม่ว่าจะใช้เทคนิคหรือเครื่องมือเฉพาะอย่างใดในใจของฉันสิ่งสำคัญที่ต้องคำนึงถึงในปรัชญา TDD คือการกำหนดความสำเร็จให้เกิดขึ้นก่อน มิฉะนั้นคุณจะโยนปาเป้าแล้ววาดจุดเป้ารอบ ๆ สถานที่ที่มันเกิดขึ้น
ในการพัฒนาการทดสอบขับเคลื่อนการพูดคุย: นี่ไม่ใช่สิ่งที่เราหมายถึงสตีฟฟรีแมนแสดงภาพนิ่งต่อไปนี้ของภาพใหญ่ TDD (ดูภาพด้านล่างคำตอบ) ซึ่งรวมถึงขั้นตอน"การเขียนการทดสอบแบบ end-to-end ที่ล้มเหลว"ซึ่งตามมาด้วย "การเขียนการทดสอบหน่วยที่ล้มเหลว" (คลิกเพื่อขยายโดยจะอยู่ที่มุมขวาบน)
ดังนั้นใน TDD การทดสอบจึงไม่ได้เป็นการทดสอบแบบหน่วย
และใช่คุณสามารถ (และอาจจะควร) เริ่มต้นด้วยการทดสอบแบบ end-to-end ระดับสูงที่ล้มเหลวก่อนที่คุณจะเขียนบททดสอบหน่วยแรก การทดสอบนี้อธิบายถึงพฤติกรรมที่คุณต้องการบรรลุ นี้จะสร้างความคุ้มครองในระดับที่มากขึ้นของการทดสอบปิรามิด เอเดรียซัตตันอธิบายประสบการณ์ LMAX ซึ่งแสดงให้เห็นว่าการทดสอบแบบ end-to-end สามารถมีบทบาทที่มีขนาดใหญ่และมีคุณค่า
ไม่มันไม่สามารถนำไปใช้กับการทดสอบประเภทอื่นได้ด้วยเหตุผลเชิงปฏิบัติง่ายๆ: การทดสอบประเภทอื่นใช้เวลาในการดำเนินการนานเกินไป
วัฏจักร TDD โดยทั่วไปคือ: เขียนการทดสอบที่ล้มเหลว, ใช้งาน, refactor code ขั้นตอนในระหว่างนั้นคือการสร้างและดำเนินการทดสอบและสิ่งเหล่านี้จำเป็นต้องรวดเร็ว หากพวกเขาไม่ใช่คนจะเริ่มข้ามขั้นตอนและจากนั้นคุณไม่ได้ทำ TDD อีกต่อไป