วันจันทร์ที่ 23 พฤศจิกายน พ.ศ. 2558
แก้ วรรณยุกต์ ลอย Jasper
https://drive.google.com/file/d/0B1xeW-nyJXKxVHV3cExJT05IUHc/view?usp=sharing
วันพุธที่ 18 พฤศจิกายน พ.ศ. 2558
Unit Testing
Unit Testing Made Easy (ตอนที่ 1)
โปรแกรมเมอร์หลายๆ คนกลัวเรื่อง Unit Testing และรู้สึกเป็นเรื่องไกลตัวที่ยากต่อการทำความเข้าใจ โดยเฉพาะอย่างยิ่งโปรแกรมเมอร์ที่ยังไม่ได้เรียนรู้การจัดระเบียบแอพพลิเคชั่นที่พัฒนาเป็นโมดูลหรืออ็อบเจ็กต์ที่ชัดเจน จะยิ่งสับสน ไม่รู้ว่า Unit Testing จะเอาไปใช้ในงานได้อย่างไร บทความนี้ผมจะเขียนแนะนำแนวทางของการนำ Unit Testing ไปใช้ โดยมีข้อกำหนดดังนี้
- คุณต้องมีรูปแบบการพัฒนาแอพพลิเคชั่นแบบ OOP ที่มีระเบียบและแบ่งงานได้ดีพอสมควร
- เข้าใจเรื่องของ OOP ในระดับพื้นฐาน เข้าใจขอบเขตการทำงานของคลาสและเนมสเปซ ไม่สับสน
- พร้อมที่จะเปลี่ยนวิธีการเขียนโปรแกรมแบบหน้ามือเป็นหลังมือ
ถ้าสามข้อนี้พร้อม ก็เริ่มต้นอ่านกันได้เลย
Unit Testing คืออะไร..?
ในการพัฒนาโปรแกรม การทดสอบโปรแกรมเป็นเรื่องที่จำเป็นมากๆ คงไม่มีโปรแกรมเมอร์คนไหนเขียนโปรแกรมโดยไม่มีการเทสหรือทดสอบโปรแกรมกันก่อน
แต่ประเด็นเรื่องการทดสอบโปรแกรมนี่แหละครับ ที่เป็นที่มาของปัญหา ว่ารูปแบบการทดสอบโปรแกรมที่ถูกต้อง ควรมีขั้นตอน ที่มาที่ไปอย่างไร และพวกฝรั่ง ซึ่งเป็นเผ่าพันธ์ที่ชอบการนิยาม ตั้งกฏเกณฑ์ และวางแนวทาง จึงพยายามสร้างกฏเกณฑ์สำหรับการทดสอบโปรแกรมเบื้องต้น โดยทั่วไปจะมีการทดสอบพื้นฐานอยู่ดังนี้ (แต่ละทฤษฏีอาจจะแตกต่างกันไป ไม่ต้องซีเรียสนะครับ)
1. Unit Testing
2. Integration Testing
3. System Testing (หรือ Production Testing)
4. Acceptance Testing
เพื่อความเข้าใจง่าย ผมจะเปรียบเทียบเรื่องแนวทางการทดสอบโปรแกรม กับเรื่องของการสร้างรถยนต์ สมมุติว่าคุณเป็นวิศวกรสร้างรถยนต์ตามสั่งให้กับเศรษฐี สิ่งแรกที่คุณจะต้องเริ่มทำก็คือการออกแบบรถยนต์ถูกไหมครับ คุณจะต้องสอบถามและเก็บข้อมูลความต้องการให้กับลูกค้ามหาเศรษฐีรายนั้น (Requirement) เมื่อออกแบบรถยนต์เป็นที่เรียบร้อย ตามแบบแปลน (System Analysis and Design)
ขั้นต่อไปก็คือการสร้างอะไหล่แต่ละชิ้น (Unit) ตามแบบแปลนที่วางไว้
ที่นี้แหละครับ เมื่ออะไหล่แต่ละชิ้นสร้างเสร็จ คุณก็จะต้องทดสอบว่า อะไหล่ชิ้นนั้นๆ ทำงานได้สมบูรณ์ไม่ผิดพลาด ไม่เสีย ไม่ว่าจะเป็นฟันเฟือง ไดชาร์ต มอเตอร์สตาร์ท แบตเตอรี่ การทดสอบดังกล่าวจะเป็นการทดสอบอะไหล่แต่ละชิ้นโดยไม่มีการเชื่อมต่ออะไหล่ใดๆ เข้าด้วยกันทั้งสิ้น และการทดสอบอะไหล่นี่แหละครับที่เราเรียกว่า Unit Testing
หลังการทดสอบ Unit Testing เรียบร้อย เราจะสามารถมั่นใจได้เลยว่า อะไหล่แต่ละตัวทำงานได้อย่างถูกต้องสมบูรณ์แน่ๆ ขั้นตอนต่อไปคือการนำอะไหล่เหล่านั้นมาประกอบกันเป็นตัวรถยนต์ หลังจากประกอบกันเรียบร้อยแล้วคุณจะต้องทดสอบรถคันนั้น และในขั้นตอนนี้คือการทดสอบที่เรียกว่า Integration Testing ครับ
ถ้าอะไหล่ทุกชิ้นทำงานถูกต้อง แต่เมื่อประกอบกันเข้าแล้ว รถยนต์ขับเคลื่อนไม่ได้ แปลว่าการเชื่อมต่อนั้นมีปัญหา ขั้นตอนการตรวจสอบแก้ไขก็จะเป็นเรื่องที่ง่ายขึ้น คือเราไม่ต้องลงไปดูอีกแล้วว่า อะไหล่นั้นเสียหรือเปล่า เพราะขั้นตอนการตรวจสอบอะไหล่นั้นเรียบร้อยไปตั้งแต่ตอนทำ Unit Testing แล้ว หากอะไหล่ไม่เสีย การเชื่อมต่อระหว่างอะไหล่ถูกต้อง รถยนต์ย่อมจะต้องขับเคลื่อนได้จริง
หลังจากนั้น ในขั้นที่ 3 รถต้นแบบที่ถูกต้องสมบูรณ์จะต้องถูกนำไปทดสอบในสถานที่จริงครับ การทดสอบ Integration Test นั้นเป็นเพียงการทดลองขับรถในโรงงานว่าขับได้จริงหรือไม่ แต่เพียงแค่นี้คุณจะเอารถออกขายเลยไม่ได้เด็ดขาด คุณจะต้องทดสอบรถคันดังกล่าว บนถนนจริงๆ สภาพแวดล้อมจริงๆ เพื่อให้มั่นใจได้ว่า รถคันนี้เมื่อนำไปขับในโลกภายนอกแล้ว สามารถทำงานได้เหมือนการทดสอบในโรงงาน ขั้นตอนนี้เราเรียกว่า System Testing ครับ (หรือ Production Testing)
เมื่อทุกอย่างเรียบร้อย วิศวกรก็จะต้องทำการส่งมอบรถกับบริษัท ทีนี้แหละครับ ลูกค้าจะเริ่มทดลองขับรถ ถ้าลูกค้าทดลองขับแล้วอัตราเร่ง การเข้าโค้ง ช่วงล่างนิ่มได้ดังใจที่ลูกค้าต้องการ ก็เป็นอันจบเรื่อง แต่ถ้าลูกค้าเรื่องมาก บอกว่าช่วงล่างแข็งเกินไป หรือเข้าโค้งได้ไม่นิ่มนวล และปฏิเสธไม่ยอมรับรถของคุณ
ทีนี้ล่ะครับที่เป็นเรื่อง เพราะรถยนต์ถูกออกแบบตาม Requirement เบื้องต้นไปแล้ว การจะมาแก้ไขในภายหลังจะเป็นเรื่องที่ยาก แต่ปัญหานี้เป็นเรื่องนอกเรื่องของบทความนี้ครับ สิ่งที่ผมอยากจะบอกก็คือ การทดสอบครั้งสุดท้ายของลูกค้านี่แหละ เรียกว่า Acceptance Testing
สรุปแบบสั้นๆ ในแง่มุมของ Software บ้าง
- Unit Testing คือการทดสอบโมดูล หรือฟังก์ชั่นแต่ละส่วนงาน ว่าทำงานได้ถูกต้อง โดยไม่จำเป็นต้องไปเชื่อมต่อกับโมดูลอื่นๆ แต่ Unit ที่ว่าอาจจะมีขนาดเล็กๆ เพียงแค่ฟังก์ชั่นเดียว หรือขนาดใหญ่เป็นอ็อบเจ็กต์ขนาดยักษ์เลยก็เป็นไปได้
- Integration Testing คือหลังจากที่โมดูลแต่ละส่วนประกอบเข้าด้วยกันแล้ว ก็ทำการทดสอบระบบในภาพรวม
- System Testing หลังจากระบบที่ทดสอบใช้งานได้แล้ว เราก็จะต้องนำระบบดังกล่าวขึ้น environment จริงๆ (เช่น Server จริง) และทำการทดสอบอีกครั้ง
- Acceptance Testing หลังจากนั้นท้ายสุดเราก็ส่งมอบให้กับลูกค้าเพื่อทำการทดสอบครั้งสุดท้าย
(การทดสอบโปรแกรมตามหลักการนี่มีหลายขั้นตอนดูดีและเป็นมืออาชีพ แต่เอาเข้าจริงชีวิตโปรแกรมเมอร์แทบไม่เจอรูปแบบการทดสอบขนาดนี้หรอกครับ ส่วนใหญ่แค่เขียนโปรแกรมให้ทันกำหนดก็ลำบากแล้ว เวลาทดสอบจริงเหลือแค่ไม่กี่วัน และก็ไม่ได้ทดสอบครบทุกขั้นตอนแบบนี้หรอก ผมพนันได้เลย)
ร่ายกันมาตั้งยาวครับ บทความซีรี่ย์นี้ผมจะเน้นไปที่เรื่องของการทำ Unit Testing โดยการใช้ Framework ที่มีชื่อว่า NUnit บน Microsoft .NET
โพสต่อไปผมจะพูดถึงแนวคิดพื้นฐานของ Unit Testing ที่ดี และเริ่มต้นการใช้งาน NUnit ด้วยตัวอย่างแบบง่ายๆ
แต่ก่อนจะถึงตรงนั้น ผมจะฝากโค้ดโปรแกรม Unit Testing เล็กๆ ซักอันให้ผู้อ่านได้ลองบริหารสมอง มาลองเดากันดูสนุกๆ ก่อนครับ ว่า NUnit นั้นมีแนวคิดและวิธีการทำงานอย่างไร จากโค้ดโปรแกรมด้านล่างนี้..?
using System; using NUnit.Framework; namespace bank { public class Account { private float balance; public void Deposit(float amount) { balance += amount; } public void Withdraw(float amount) { balance -= amount; } public void TransferFunds(Account destination, float amount) { } public float Balance { get { return balance; } } } } namespace bank { [TestFixture] public class AccountTest { [Test] public void TransferFunds() { Account source = new Account(); source.Deposit(200.00F); Account destination = new Account(); destination.Deposit(150.00F); source.TransferFunds(destination, 100.00F); Assert.AreEqual(250.00F, destination.Balance); Assert.AreEqual(100.00F, source.Balance); } [Test] public void DepositFunds() { Account source = new Account(); source.Deposit(200.00F); Assert.AreEqual(200.00F, source.Balance); } } } namespace UnitTestDemo { public class MyAccountingSoftware { public static void Main() { bank.Account DemoAccount = new bank.Account(); DemoAccount.Deposit(1000.00F); DemoAccount.Withdraw(500.50F); Console.WriteLine("Our account balance is {0}", DemoAccount.Balance); } } }
แล้วโพสหน้าผมจะมาเฉลย ระหว่างนี้ไปโหลด NUnit มาติดตั้งที่เครื่องก่อนนะครับ โดยคลิกไปที่นี่
แล้วเจอกันใหม่ตอนหน้าครับ