[Dev] ทำ Test Driven Development บน Visual Studio กันเถอะ

Test Driven Development (TDD) เป็นแนวคิดของขั้นตอนการพัฒนาซอฟแวร์ หากใครไม่รู้จัก TDD ลองจิ้มไปที่ Link หรือถาม Google ดูก่อนนะครับ

Test Driven Development

ขอยืมรูปมาจาก deviantart.com

เห็นรูปด้านบนแล้ว อย่าเพิ่งคิดว่าจะมาแนะนำเกมส์นะครับ แค่ขอยืมรูปมาประกอบเฉย ๆ

ในบทความตอนนี้ เราจะมาดูกันว่า Visual Studio นั้น สามารถทำ TDD ได้อย่างไร

 

List of contents

 

Test Driven Development Cycle

ก่อนอื่น มาดูวงจรการทำ TDD กันก่อน

Test Driven Development Cycle
Test Driven Development Cycle

ขอยืมรูปมาจาก https://github.com/mjhea0/flaskr-tdd

ขั้นตอนง่าย ๆ 3 ขั้นตอน ของ TDD ก็คือ

  1. ทำให้ Fail
  2. แก้ให้ Pass
  3. แก้ไขให้ดี

สำหรับ Visual Studio นั้น ได้เตรียมเครื่องมือให้เราทำ TDD ไว้แล้ว เรามาดูกันว่า เราจะทำ TDD บน Visual Studio ได้อย่างไร

 

Add Test Project

คลิกขวาในหน้าต่าง Solution Explorer ใน Visual Studio แล้วเลือก Add > New Project…

เมนู Add > New Project...
เมนู Add > New Project…

เลือก Test Project ภายใต้ Language ที่ต้องการ ในตัวอย่างเป็นการเลือกใช้ Visual Basic หากใครถนัด Visual C# หรือ Visual C++ ก็มีให้เลือกใช้

เลือก Test Project
เลือก Test Project

เมื่อ Add Test Project แล้ว จะเห็น Project เพิ่มเข้ามาใน Solution จะเห็นว่ามีไฟล์ UnitTest1.vb อยู่ใน Test Project

จะมี Test Project เพิ่มเข้ามา
จะมี Test Project เพิ่มเข้ามา

ลองเปิด UnitTest1.vb ดู ก็จะเห็น Source code ดังนี้

คลิกขวาที่ Test Project แล้วเลือกเมนู Add Reference…

เมนู Add Reference...
เมนู Add Reference…

แล้วเลือกไปที่ Project ที่ต้องการทำ TDD

เลือก Project ที่จะทำ TDD
เลือก Project ที่จะทำ TDD

สุดท้าย อย่าลืมกำหนดให้ Test Project เป็น StartUp Project เพื่อว่าเมื่อเราสั่ง Run จะได้มา Run ที่ Test Project

กำหนดให้ Test Project เป็น StartUp Project
กำหนดให้ Test Project เป็น StartUp Project

ตอนนี้ Test Project เราก็พร้อมทำงานแล้ว ถ้าลอง Run ดู จะเห็นหน้าต่าง Test Results ออกมาให้ดู ดังนี้

หน้าต่าง Test Results
หน้าต่าง Test Results

หากไม่พบ สามารถเปิดหน้าต่าง Test Results ได้จากเมนู Test > Windows > Test Results

ในรูปตัวอย่างด้านบน จะเห็นว่า TestMethod1 มี Result เป็น Pass เพราะเรายังไม่ได้ทำการเขียน Test Code เลย

กรณีที่เรามีหลาย Test Method การ Run จะทำกับทุก Test Method หากต้องการ Test เฉพาะ Method ใด Method หนึ่ง สามารถคลิกขวาที่ Source code ของ Method นั้น แล้วเลือก Run Tests

Run Test Method ที่สนใจ
Run Test Method ที่สนใจ

 

ต่อไปเราจะมาเริ่มขั้นตอนของการทำ TDD กัน โดยตัวอย่างในบทความนี้ ผมจะต้องสร้าง Class สำหรับจัดการข้อมูลตัวเลขจำนวนเต็มบวก โดยสามารถแปลงเป็นคำอ่านในภาษาไทย ยกตัวอย่างเช่น Input เป็น “321” ต้องการ Output เป็น “สามร้อยยี่สิบเอ็ด”

จากโจทย์ข้างต้น Feature ที่ต้องมีใน Class คือ

  1. รับข้อมูลเป็นตัวเลขจำนวนเต็มบวกได้
  2. แปลงข้อมูลที่รับมาให้เป็นคำอ่านภาษาไทยได้

ใน Feature ที่ 1 จะ Design ให้รับค่าได้ผ่าน

  1. Constructor
  2. Property

ส่วนใน Feature ที่ 2 จะ Design ให้คืนค่าด้วย Method

เมื่อ Requirement พร้อม Design พร้อม ก็เริ่มขั้นตอนการทำ TDD แล้ว

 

Red Fail

ขั้นตอนแรกของการทำ TDD บน Visual Studio นั่นคือ Red Fail จะเป็นการทำในฝั่งของ Test Project ก็คือการทำ Test Method

จากที่ Design ข้างต้น ใน Feature ที่ 1 (a) สามารถสร้างเป็น Constructor ได้ 5 ตัว คือ

  1. Parameter 1 ตัว ชนิด Byte
  2. Parameter 1 ตัว ชนิด UShort
  3. Parameter 1 ตัว ชนิด UInteger
  4. Parameter 1 ตัว ชนิด ULong
  5. ไม่มี Parameter

และใน Feature ที่ 1 (b) สามารถ Read/Write เป็นชนิด ULong

ส่วน Feature ที่ 2 นั้น จะ Return เป็นชนิด String

เราก็จะทำ Test Method ออกมาได้เป็นดังนี้

หลังจากนั้น จะมาเริ่มเขียน Logic ในแต่ละ Test Method กัน

ใน Test Method Test1_Case1 เราจะ Test กรณี Constructor มี Parameter 1 ตัว ชนิด Byte และ Read ข้อมูลผ่าน Property เป็นชนิด ULong ได้ และ Output ต้องมีค่าเท่ากับ Input

แน่นอนว่า Code ข้างต้น บรรทัดที่ 2 และ 3 จะ Error เนื่องจาก Class ThaiNumber ยังไม่ได้สร้าง Constructor ที่มี Parameter 1 ตัว ชนิด Byte และยังไม่ได้สร้าง Property ที่เป็นชนิด number

เพราะฉะนั้น Test Method Test1_Case1 จะยัง Run ไม่ได้ จึงจำเป็นต้องไป Design ในส่วนของ Class ThaiNumber ให้เรียบร้อยก่อน ตาม Test Method นี้ ก็จะได้ออกมาดัง Class Diagram นี้

Class ThaiNumber ตาม Test Method Test1_Case1
Class ThaiNumber ตาม Test Method Test1_Case1

เมื่อ Design Class ThaiNumber เรียบร้อย โดยยังไม่ต้อง Implement code ภายใน Constructor และ Property ในส่วนของ Test Method ก็จะไม่ Error แล้ว

หลังจากนั้น ให้ทำการกำหนดว่า Test Method นี้ ต้องการตรวจสอบเงื่อนไขที่ว่า Output ต้องมีค่าเท่ากับ Input ดังนี้

เราจะใช้ Class Assert ในการกำหนดเงื่อนไข โดย Code ข้างบน มีความหมายว่า ถ้าตัวแปร ulngNum (ซึ่งก็คือ Output) มีค่าเป็น 255 (ซึ่งก็เท่ากับค่าที่ใช้เป็น Input) ถือว่าผ่านเงื่อนไข

ยังไม่ต้อง Run เราก็สามารถตอบได้ทันทีว่า ไม่ผ่าน แน่ ๆ เพราะเรายังไม่ได้เขียน Code ใน Class ThaiNumber เลย จริงไม๊

ลองรันดู จะได้ผลลัพธ์ ดังนี้

ผลการ Run Test Method
ผลการ Run Test Method Test_Case1

ก็เท่านี้ Test Method Test1_Case1 ก็ถือว่า Success แล้ว Ugh!

งงกันไม๊~!! ก็ ขั้นตอนนี้ เราทำ Red Fail อยู่ไง เห็นไม๊ ใน Test results เป็น Icon สีแดง มีคำว่า Failed แล้ว Big Smile

 

Green Pass

ในขั้นตอน Green Pass จะเป็นการทำในฝั่งของ Project งาน

ใน Test Method Test1_Case1 นั้น สิ่งที่เรายังไม่ได้ Implement ใน Class ThaiNumber เลย ก็คือ ส่วนของ Constructor และ Property

ซึ่งเราควรจะ Focus เนื้องานไปที่ ทำยังไงให้ Test Method Test1_Case1 นั้น ผ่านเท่านั้น

  • บรรทัดที่ 2 เป็นส่วนของ Field (ตัวแปรภายใน Class) ชื่อ _number ที่เป็นชนิด Byte เพื่อไว้เก็บข้อมูล
  • บรรทัดที่ 4-6 เป็นส่วนของ Constructor สามารถรับค่าทาง Parameter ชนิด Byte ได้ และเก็บลง Field _number ได้
  • บรรทัดที่ 8-15 เป็นส่วนของ Property ซึ่งเราจะเขียน Code เฉพาะ Property Get เพื่อให้ Read ค่าได้ (สำหรับในส่วนของ Property Set ยังไม่มีความจำเป็นต้องเขียน เนื่องจากอยู่นอกเหนือส่วนที่เรากำลัง Focus)

ลอง Run Test Method ดูอีกที

ผลการ Run Test Method
ผลการ Run Test Method

Green Pass แล้ว เห็นไม๊~!! Embarrassed

 

Refactor

ในขั้นตอน Refactor จะเป็นการปรับปรุง Code ในฝั่งของ Project งาน โดยในตัวอย่างข้างต้น เป็น Code ที่ตรงไปตรงมา จึงไม่มีอะไรให้ปรับปรุง I Surrender!

 

New Cycle

งั้นมาเริ่ม Cycle ต่อไปกันเลยดีกว่า

ทำ Red Fail บน Test Method Test1_Case2 ได้ดังนี้

แล้ว Green Pass บน Class ThaiNumber ได้ดังนี้ (เพิ่มเติมจากของเดิม)

ลองรันดู อ้าว~!! ทะไม Fail ล่ะ มันน่าจะ Pass นี่นา Hit with Ball

ผลการ Run Test Method
ผลการ Run Test Method

ลองดับเบิ้ลคลิกไปที่ Result ดู จะพบกับรายละเอียด สังเกตุในส่วนของ Error Message จะเห็นว่า เกิด OverflowException แปลว่ามีการใส่ค่าตัวแปรที่มีค่าเกินกว่าที่ตัวแปรจะรับได้

และที่ Error Stack Trace สามารถบอกได้ว่า Error ที่เกิดขึ้น เกิดที่ไหน บรรทัดที่เท่าไหร่ ในตัวอย่างนี้ มี Error เกิดขึ้นใน 2 จุด ลองวิเคราะห์ดู เรากำลังทำ Green Pass เพราะฉะนั้น จุดที่ต้องไปแก้ ต้องอยู่ใน Class ThaiNumber ว่าแล้วก็จิ้ม Link ตรงที่ Pointer ชี้อยู่ในรูป ก็จะเปิดไปยัง Class ThaiNumber บรรทัดที่ 10 ได้ทันที

รายละเอียดผลการ Run Test Method
รายละเอียดผลการ Run Test Method

ซึ่งเราก็จะได้พบว่า เรานำค่าตัวแปรชนิด UShort ไปเก็บลงตัวแปร Byte ที่เก็บข้อมูลในขนาดที่เล็กกว่า เพราะฉะนั้น เราก็จะไปปรับตัวแปร _number ให้เป็นชนิด UShort ซะ เท่านี้ขั้นตอน Green Pass ก็ผ่านแล้ว

ต่อด้วย Refactor ซึ่งพอจะเห็นแล้วว่า ควรจะ Refactor ที่ตัวแปร _number ซะ เพื่อให้ Test Method ต่อ ๆ ไปใน Cycle อื่น ๆ ไม่เกิดปัญหาเหมือน Cycle นี้อีก

ก่อนจบ Cycle อย่าลืม Run Test Project ทั้งหมดอีกครั้ง เพื่อให้มั่นใจว่า Test Method ใน Cycle นี้ ไม่มี Effect ต่อ Test Method ใน Cycle ก่อนหน้านี้

ผลการ Run Test Project
ผลการ Run Test Project

จบ Cycle ที่ 2 แล้วครับ Big Smile

 

ในบางครั้ง เราอาจจะทำ Red Fail ในทุกเงื่อนไขให้ครบก่อน แล้วค่อย ๆ ทำ Green Pass ไปทีละส่วน ๆ ก็จะสามารถคำนวณ Progress ของงานเราได้ว่า งานเราเสร็จไปกี่ % แล้ว

Code ต่อไปนี้ จะทำการทำ Test Method ให้ครบทุกเงื่อนไข

ลอง Run Test Project ดู

ผลการ Run Test Project
ผลการ Run Test Project

จะเห็นว่า ผ่านไป 2 Test Method จากทั้งหมด 6 Test Method แล้ว ก็เท่ากับงานเสร็จไปแล้ว 33.33%

สำหรับใครที่มองว่า ทำ TDD นั้น มีความยุ่งยาก เสียเวลา ถ้าไม่ทำ TDD คุณก็ต้อง Test เองอยู่ดี แล้วการ Test อย่างไม่มีระบบ มันเสียเวลากว่าเยอะนะ

สำหรับบทความตอนนี้ ขอตัดจบเพียงเท่านี้ก่อน ขอตัวไปทำอีก 66.67% ที่เหลือ ให้เป็น Green Pass ก่อนนะครับ

Leave a Reply

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.