อะไรคือข้อเสียของการเขียนโค้ดก่อนที่จะทำการทดสอบหน่วย?


33

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

เมื่อฉันเห็นข้อเสนอแนะจำนวนมากเพื่อเริ่มเขียนการทดสอบจากนั้นไปยังการเขียนโปรแกรมข้อเสียเปรียบถ้าฉันทำอย่างอื่น - เขียนโค้ดแล้วทดสอบหน่วย?


7
+1 สำหรับการถามว่าทำไมการฝึกฝนแบบใดแบบหนึ่งคือ "แนวปฏิบัติที่ดีที่สุด" ก่อนที่จะนำมาใช้
TaylorOtwell

คำตอบ:


37

สีแดงคือคำตอบ สีแดงคือสิ่งที่คุณได้รับจากวัฏจักรสีแดงเขียว - แดง - ตัวทำละลายที่คุณไม่สามารถทำได้ทดสอบครั้งสุดท้าย ก่อนอื่นให้เขียนการทดสอบที่ล้มเหลว ดูมันล้มเหลว นั่นคือสีแดงของคุณและมันสำคัญ มันบอกว่า: ฉันมีข้อกำหนดนี้และฉันรู้ว่ารหัสของฉันไม่เป็นที่พอใจ ดังนั้นเมื่อคุณไปที่ขั้นตอนที่ 2 (สีเขียว) คุณรู้ด้วยความมั่นใจมากพอ ๆ กับที่ตอนนี้โค้ดของคุณตรงตามข้อกำหนดนั้น คุณรู้ว่าคุณได้เปลี่ยนรหัสฐานในลักษณะที่เป็นไปตามข้อกำหนด

ความต้องการ (การทดสอบ) ที่พัฒนาขึ้นหลังจากโค้ดตามรหัสทำให้คุณมั่นใจในความมั่นใจนั้น


+1 - จุดและจุดที่ยอดเยี่ยม! ขอบคุณสำหรับความคิดเห็นของคุณ!
k25

7
การทดสอบ! = ความต้องการ ทั้งการทดสอบและรหัสควรได้มาจากข้อกำหนด
Bart van Ingen Schenau

2
@Bart van Ingen Schenau: ความแข็งแกร่งของ TDD นั้นแม่นยำว่าการทดสอบนั้นเป็นข้อกำหนด นอกจากนี้ยังเป็นข้อกำหนดสำหรับการปฏิบัติการ
mouviciel

1
@Bart: การทดสอบหน่วยมักจะมีรายละเอียดมากเกินไปสำหรับความต้องการของลูกค้า (ระดับสูง) แต่ความคิดนั้นยังคงอยู่โดยเฉพาะอย่างยิ่งถ้าเราพิจารณาการทดสอบในระดับที่สูงขึ้นเช่นการทดสอบการยอมรับอัตโนมัติซึ่งเมื่อเขียนแล้ว นั่นคือสาระสำคัญของ "การยอมรับการทดสอบความคล่องตัว"
Martin Wickman

3
TDD ไม่ได้เกี่ยวกับการทดสอบมันเป็นเรื่องของสเปค การทดสอบที่สร้างขึ้นในวิธีการ TDD เป็นวิธีการสื่อสารระหว่างผู้พัฒนาและลูกค้าสำหรับการตกลงในผลิตภัณฑ์ที่ควรทำ
mouviciel

18

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

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


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

2
แต่ถ้าการทดสอบผ่าน? การทดสอบอาจผ่านเพราะไม่ได้ใช้รหัสที่น่าสนใจ สิ่งนั้นไม่สามารถเกิดขึ้นได้ภายใต้ TDD เพราะการทดสอบนั้นจะล้มเหลวในขั้นต้นและถ้า - ไม่เช่นนั้นคุณจะไม่ไปยังขั้นตอนที่ 2 จนกว่าคุณจะทำการแก้ไข ดังนั้นจึงมีโหมดความล้มเหลวในการทดสอบครั้งล่าสุดที่ไม่มีอยู่ในการทดสอบก่อน
Carl Manaster

@Carl Manaster - ใช่คุณมีจุดที่ถูกต้อง หลังจากที่ฉันเขียนรหัสฉันก็ตระหนักดีถึงข้อกำหนดและดังนั้นกรณีทดสอบหน่วยของฉันจะถูกต้อง (นึกคิด) หากกรณีทดสอบของฉันผ่านฉันจะบอกว่ารหัสถูกต้องหากการทดสอบล้มเหลวฉันจะทำตามสิ่งที่ฉันพูด แต่ฉัน 100% ยอมรับว่าคุณมีจุดที่ถูกต้องที่นั่น
k25

@ k25: ประเด็นคือถ้ากรณีทดสอบของคุณผ่านคุณยังไม่รู้ว่ารหัสถูกต้องหรือไม่ กรณีทดสอบอาจผิด
อานนท์

@Anon - ใช่คุณพูดถูกฉันจะนำคดีนี้ไปพิจารณาด้วย
k25

12

ที่จริงแล้วผู้คนจำนวนมากกำลังง่วนอยู่กับ TDD นั้นเกี่ยวกับการทดสอบถึงแม้ว่าพวกเขาจะลืมตัวอักษรอีกสองตัวในอักษรย่อ บางสิ่งบางอย่างซึ่งสามารถอ่านได้ที่นี่: TDD โดยไม่ต้อง TหรือTDD ไม่ได้เกี่ยวกับการทดสอบ

สิ่งนี้คือฉันได้เรียนรู้สิ่งอื่น ๆ มากมายที่ถักด้วย TDD อย่างแน่นหนา มันไม่สำคัญว่าถ้าคุณทำทดสอบครั้งแรก: เรื่องอะไรความคิดเกี่ยวกับการออกแบบซอฟแวร์

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

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

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

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


1
+1 สำหรับ SOLID เกิดขึ้นกับคุณตามธรรมชาติเมื่อคุณคิดถึงการออกแบบซอฟต์แวร์
ocodo

+1 (จริง ๆ แล้วฉันต้องการให้ +10 แต่ฉันทำไม่ได้) ความคิดของฉัน - รายการคะแนนของคุณดีมาก นั่นเป็นเหตุผลหนึ่งที่ฉันถามคำถามนี้ ฉันรู้สึกว่าชั้นเรียนมีมากขึ้นเมื่อฉันเริ่มเขียนการทดสอบหน่วยหลังจากฉันเขียนรหัส แต่ฉันต้องการเห็นข้อดี / ข้อเสียของทั้งสองฝ่ายขอบคุณสำหรับความคิดเห็นของคุณ!
k25

10

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


4

หากคุณเขียนแบบทดสอบก่อนจะให้โอกาสคุณคิดเกี่ยวกับการออกแบบของคุณก่อนที่การออกแบบนั้นจะ "cast in stone"

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


+1 สำหรับจุดแรก แต่ไม่ถึงระดับพารามิเตอร์จะเกิดอะไรขึ้นถ้าการออกแบบได้พูดคุยกับผู้อื่นและยอมรับ?
k25

@ k25 - หากบางสิ่งยากที่จะใช้ตามที่ออกแบบมามันต้องใช้ความคิดมากกว่านี้ บางครั้ง - บ่อยครั้งมาก - มันเป็นงานที่ยาก แต่บ่อยครั้งที่มันสามารถลดลงเพื่อให้งานง่ายขึ้น ฉันไม่มีลิงค์ แต่ Gosling หรือ Goetz ได้ให้สัมภาษณ์เกี่ยวกับการออกแบบ API เมื่อไม่กี่ปีที่ผ่านมา ... คุ้มค่ากับ Googling
Anon

แน่นอนขอบคุณสำหรับพอยน์เตอร์ฉันจะดูพวกเขาอย่างแน่นอน ...
k25

2

ในขณะที่ฉันเห็นคำแนะนำมากมายที่จะเริ่มเขียนข้อสอบแล้วไปที่การเขียนโปรแกรม

มีเหตุผลที่ดีสำหรับเรื่องนี้

ถ้าคุณพูดว่า "ทำในสิ่งที่ถูกต้อง" ผู้คนจะทำสิ่งที่โง่ที่สุดและบ้าคลั่งที่สุด

หากคุณพูดว่า "เขียนการทดสอบก่อน" คนอย่างน้อยอาจพยายามทำสิ่งที่ถูกต้อง

อะไรคือข้อเสียถ้าฉันใช้วิธีอื่น - เขียนโค้ดจากนั้นหน่วยทดสอบ?

โดยปกติแล้วการทดสอบหมัดและการออกแบบที่จะต้องทำใหม่เพื่อให้สามารถทดสอบได้

อย่างไรก็ตามนั่นเป็นเพียง "ปกติ" บางคนมีวิวัฒนาการการออกแบบและการทดสอบในแบบคู่ขนาน บางคนใส่รหัสที่สามารถทดสอบได้และเขียนการทดสอบโดยไม่มีการทำใหม่

กฎ "ทดสอบก่อน" มีไว้เพื่อสอนและสั่งสอนผู้ที่ไม่มีเงื่อนงำโดยเฉพาะ

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

เมื่อฉันไปเที่ยวประเทศที่อยู่ทางซ้ายมือการมองทางด้านซ้ายจะทำให้ฉันถูกฆ่าได้

กฎมีการระบุไว้อย่างมากด้วยเหตุผล

สิ่งที่คุณทำคือปัญหาของคุณเอง


2

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

  • วิธีทดสอบรหัส
  • อินเทอร์เฟซที่รหัสต้องแสดงเพื่อให้สามารถทดสอบได้

ถ้าคุณทำอะไรที่เรียบง่ายมันอาจไม่สำคัญว่าคุณจะเขียนแบบไหนก่อน (แม้ว่ามันจะดีในการฝึกฝนนิสัยการทดสอบครั้งแรก) เพราะการทดสอบจะง่ายและอินเทอร์เฟซจะชัดเจน

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


1

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

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

หนังสือ: เบ็ค, เค. การพัฒนาขับเคลื่อนทดสอบโดยตัวอย่าง

ตัวอย่างที่ดี: http://jamesshore.com/Blog/Lets-Play/


+1 - คะแนนที่ดี (โดยเฉพาะวันที่ 1) และขอบคุณสำหรับลิงก์!
k25

0

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

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

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

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