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


9

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

สิ่งที่มีประโยชน์ที่สุดสำหรับฉันคือวิธีที่มันดูดซับบทบาทของการทดสอบการถดถอย

ฉันยังไม่ได้สร้างอะไรเลยที่แยกพฤติกรรมทดสอบต่าง ๆ โดยเฉพาะซึ่งเป็นอีกส่วนใหญ่ของภาพที่ฉันรู้

ดังนั้นคำถามนี้เพื่อขอคำแนะนำเกี่ยวกับสิ่งที่การทดสอบครั้งแรกที่ฉันอาจเขียนสำหรับงานพัฒนาต่อไปนี้: ฉันต้องการผลิตรหัสที่ห่อหุ้มการดำเนินงานในแบบของผู้ผลิต / ผู้บริโภค

ฉันหยุดและตัดสินใจที่จะเขียนคำถามนี้หลังจากที่ฉันเขียนรหัสนี้ (สงสัยว่าถ้าฉันสามารถใช้ TDD จริงในเวลานี้)

รหัส:

interface ITask
{
    Guid TaskId { get; }
    bool IsComplete { get; }
    bool IsFailed { get; }
    bool IsRunning { get; }
}

interface ITaskContainer
{
    Guid AddTask(ICommand action);
}

interface ICommand
{
    string CommandName { get; }
    Dictionary<string, object> Parameters { get; }
    void Execute();
}

คุณควรเขียนการทดสอบก่อนแล้วจึงเชื่อมต่อ! แนวคิดทั้งหมดคือ TDD นั้นมีไว้สำหรับ API ของคุณ

1
หนึ่งเขียนทดสอบสำหรับอินเทอร์เฟซที่ยังไม่มีอยู่ได้อย่างไร พวกเขาจะไม่ได้รวบรวม
Robert Harvey

5
นั่นคือการทดสอบที่ล้มเหลวครั้งแรกของคุณ
Cori

คำตอบ:


10

เริ่มต้นด้วยแนวคิดนี้:
1) เริ่มต้นด้วยพฤติกรรมที่คุณต้องการ เขียนทดสอบ ดูการทดสอบล้มเหลว
2) เขียนโค้ดให้เพียงพอเพื่อให้การทดสอบผ่าน ดูการทดสอบทั้งหมดที่ผ่าน
3) ค้นหารหัสซ้ำซ้อน / เลอะเทอะ -> refactor ดูการทดสอบยังคงผ่าน ไปที่ 1

ดังนั้นใน # 1 สมมติว่าคุณต้องการสร้างคำสั่งใหม่ (ฉันกำลังขยายไปถึงวิธีการใช้งานคำสั่งดังนั้นทนกับฉัน) (นอกจากนี้ฉันจะเป็นบิตในทางปฏิบัติมากกว่า TDD มาก)

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

@Test
public void instantiateMakeMyLunch() {
   ICommand command = new MakeMyLunchCommand();
   assertEquals("makeMyLunch",command.getCommandName());
}

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

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

สมมติว่าทดสอบง่ายสำหรับ:

@Test
public void checkThatMakeMyLunchIsSuccessful() {
   ICommand command = new MakeMyLunchCommand();
   command.execute();
   assertTrue( Lunch.isReady() );
}

ในบางครั้งสิ่งนี้ยากกว่าและสิ่งที่คุณต้องการทำจริงๆคือทดสอบความรับผิดชอบของหัวเรื่องภายใต้การทดสอบ (MakeMyLunchCommand) บางทีความรับผิดชอบของ MakeMyLunchCommand คือการโต้ตอบกับตู้เย็นและไมโครเวฟ ดังนั้นเพื่อทดสอบคุณสามารถใช้ตู้เย็นจำลองและไมโครเวฟจำลอง [ตัวอย่างกรอบจำลองสองตัวอย่างคือMockitoและnMockหรือดูที่นี่ ]

ในกรณีนี้คุณจะทำบางอย่างเช่นรหัสหลอกต่อไปนี้:

@Test
public void checkThatMakeMyLunchIsSuccessful() {
   Fridge mockFridge = mock(Fridge);
   Microwave mockMicrowave = mock(Microwave);
   ICommand command = new MakeMyLunchCommand( mockFridge, mockMicrowave );
   command.execute();
   mockFramework.assertCalled( mockFridge.removeFood );
   mockFramework.assertCalled( microwave.turnon );
}

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

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

ค้นหาสมดุลที่เหมาะสมกับระบบของคุณ

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


หากฉันไม่ได้เขียนส่วนต่อประสานไว้ล่วงหน้าคำถามใดจะนำไปสู่การสร้างวิธีดำเนินการ () - ความพยายามเริ่มต้นบางส่วนของฉันในการเริ่ม TDD จนตรอกเมื่อฉันไม่มี "ขั้นตอน" เพื่อกระตุ้นการทำงานเพิ่มเติม - ฉันได้รับ ความรู้สึกมีปัญหาไก่ / ไข่แฝงที่จะต้องมีการ sidestepped
Aaron Anodide

1
คำถามที่ดี! หากคำสั่งเดียวที่คุณทำคือ "MakeMyLunchCommand" วิธีการอาจเริ่มต้นด้วย ".makeMyLunch ()" ซึ่งก็คงจะดี จากนั้นคุณสร้างคำสั่งอื่น ("NapCommand.takeNap ()") ยังไม่มีปัญหากับวิธีการต่าง ๆ จากนั้นคุณเริ่มใช้มันในระบบนิเวศของคุณซึ่งเป็นไปได้ว่าคุณถูกบังคับให้พูดคุยทั่วไปในส่วนต่อประสาน ICommand โดยทั่วไปคุณมักจะเลื่อนการสรุปจนถึงช่วงเวลาสุดท้ายที่มีความรับผิดชอบเนื่องจาก YAGNI [ en.wikipedia.org/wiki/You_ain't_gonna_need_it ] =) ในบางครั้งคุณรู้ว่าคุณกำลังจะไปที่นั่นเพื่อเริ่มต้นกับมัน
jayraynet

(นอกจากนี้ยังมีข้อสันนิษฐานที่ว่าคุณกำลังใช้ IDE ที่ทันสมัยที่ทำให้การรี
แฟคเจอริ่ง

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