bf321947675de864ac980948a6c835a82768a0eb48091d32e432fabcf4165666
อ่านเจอบทความเรื่อง JUnit Test Infected: Programmers Love Writing Tests
มันโดนใจมากๆ ดังนั้น จึงเอามาแปล และ สรุปดีกว่า

ในการพัฒนา software นั้นเรามักไม่รวมการทดสอบเข้าไปในช่วงของการพัฒนามากนัก
ซึ่งเป็นการปิดกั้นการวัดความคืบหน้าในการพัฒนาเลยนะ
ดังนั้นคุณจะบอกได้อย่างไรว่า

  • เมื่อไรจะเริ่มทำงานนั้นๆ
  • เมื่อไรจะหยุดทำงานนั้นๆ

ดังนั้นมาเปลี่ยนวิธีการพัฒนาโดยนำการทดสอบเข้ามาร่วมด้วย
เพื่อทำให้รู้ว่าเราทำงานอะไรอยู่
เพื่อทำให้รู้ว่าสิ่งที่เราทำมีความคืบหน้าเท่าไร
เพื่อทำให้รู้ว่าเกิดผลกระทบอะไรบ้าง
เพื่อทำให้เรา focus กับสิ่งที่กำลังทำ

ดังนั้นมาเขียน test กันเถอะ …

เริ่มต้นที่ปัญหา ทำไม developer ถึงไม่เขียน test ?

ผมเชื่อว่า developer ทุกๆ คนรู้ว่า การทดสอบ หรือ การเขียน test มันดี และ ควรทำนะ
แต่มี developer เพียงน้อยนิดที่ ทำ !!
สิ่งที่น่าสนใจก็คือ ทำไมไม่ทำล่ะ ?

คำตอบที่มักจะได้ยินก็คือ

  • งานมันเร่งนะ
  • ไม่มีเวลาหรอก
  • แค่พัฒนาให้มันเสร็จ ยังยากเลย เขียน test หรอ หวังไปเถอะ
  • ถูกกดดันด้วย dead line
  • มันลด productivity ของเราไป
  • เราต้องการความเร็วนะ

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

ดังนั้น คุณจึงได้รับความกดดันสูงขึ้นใช่ไหม ?
สุดท้ายคนที่ได้รับผลกระทบมากสุดๆ คือ คุณใช่ไหม ?
ดังนั้น ยังจะทำในทิศทางเดิมๆ อยู่ แล้วคิดว่าจะได้ผลลัพธ์ที่ดีขึ้นอยู่กันอีกหรือ ?

วิธีการหนึ่งที่น่าสนใจก็คือ
การเขียน unit test เพื่อให้เราทดสอบสิ่งที่เล็กๆ
ไปแบบ step-by-step เพื่อสร้างงานใหญ่ๆ ออกมา
มันคือการเปลี่ยนแปลงวิธีการทำงานไปเลย
เหมือนการตีลังกาพัฒนาระบบงาน

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

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

มาดูตัวอย่างการพัฒนาดีกว่า เพื่อให้เห็นภาพ

โดยปกติที่เราพัฒนาระบบนั้น เรามักจะเขียน code และ test อยู่เสมอ
แต่การทดสอบจะมีหลายรูปแบบ เช่น

  • ใช้ความรู้สึก
  • run ให้เห็นว่าทำงานได้
  • เขียน code เล็กน้อย เพื่อให้รู้ว่า สิ่งที่สร้างมันทำงานได้นะ

ตัวอย่างเป็นการสร้างระบบการคำนวณค่าเงินในสกุลต่างๆ
โดยเราจะเริ่มต้นเขียน code กันเลย
แน่นอนว่าต้องสร้าง class Money ขึ้นมาประมาณนี้

ถ้าต้องการจะบวก Money ในสกุลเดียวกัน ทำยังไงดีล่ะ ?
คุณก็จะบอกเลยว่า มันง่ายนะ ทำเท่านี้เอง
เพียงแค่เพิ่ม method add() เข้ามาสิ

แต่เดี๋ยวก่อนนะ !!!
แทนที่จะเขียน code ไปเลยแบบนี้
เราจะรู้ได้อย่างไรว่า สิ่งที่เราเพิ่มไปทำงานได้อย่างถูกต้อง
และต้องการ feedback กลับมาอย่างรวดเร็ว
ดังนั้น เรามาลองฝึกการเขียน code ด้วยแนวคิด

“code a little, test a little, code a little, test a little”

ดังนั้นมาเขียน test สำหรับการบวก Money ในสกุลเงินเดียวกันไหม ดังนี้
เริ่มด้วยการเขียน test ชื่อว่า MoneyTest
โดย test case แรกคือ การบวกเงินในสกุลเงินเดียวกัน ดังนี้

คำอธิบายของ test case นี้ประกอบไปด้วย 3 ส่วนคือ

  • Arrange เป็นการสร้าง object ต่างๆ ที่จะใช้ในการทดสอบ ซึ่งจะเรียกว่า test fixture จากตัวอย่างคือ object ของ Money
  • Act ทำการเรียกใช้งานส่วนที่ต้องการทดสอบ ด้วย test fixture ที่กำหนดไว้
  • Assert สำหรับการตรวจสอบผลการทำงาน ว่าเป็นไปตามที่คาดหวังหรือไม่

แน่นอนว่า ถ้าทำการ run MoneyTest มันจะต้องไม่ผ่านอย่างแน่นอน
เนื่องจากในส่วนของ Assert นั้น ทำการเปรียบเทียบระหว่าง 2 object
ซึ่งในภาษา Java นั้นเราจะต้องทำการ override method equals() จาก class Object ขึ้นมาด้วยนะ
ดังนั้น มาเริ่มสร้าง method equals() กัน
แต่เดียวก่อน มีคำถามดังนี้

คำถาม
เราจะต้องทำอะไรก่อน ที่จะสร้าง method equals() ใน class Money ?
คำตอบ
ก็ต้องสร้าง test case ก่อนไงล่ะ
ไปที่ละก้าวเล็กๆ นะครับ
เริ่มเขียน test case ชื่อว่า equalsMoney ดังนี้

คำอธิบาย
ใน test case นี้ต้องทำการตรวจสอบว่า
แต่ละ object เป็น object ชนิดเดียวกัน
แต่ละ object มีค่าเท่ากัน และ มีสกุลเงินเดียวกัน

จากนั้นทำการสร้าง method equals() ใน class Money ดังนี้

และให้ทำการ run Unit test อีกรอบจะพบว่า ผ่านทั้งหมดดังนี้
Screen Shot 2558-02-25 at 2.13.13 PM

ในตอนนี้เรามี 2 test case แล้วนะ

แต่สังเกตไหมว่า เกิด duplicate code (code ที่ซ้ำซ้อน) ขึ้นมาใน class MoneyTest ?
ถ้าไม่เห็นคงต้องไปหาหมอกันได้แล้ว …
ดังนั้น เราสามารถจัดการ code ที่มันซ้ำซ้อนกัน
ด้วยการย้าย test fixture ไปไว้ในส่วนของการ setup ของ test ดังนี้

ในกรณีที่ว่า เรามี test หลายไฟล์มากๆ เช่น

  • MoneyTest
  • MoneyTest2
  • MoneyTest3

และเราต้องการแบ่งกลุ่มการทดสอบล่ะ จะทำได้ไหม ? เช่น
กลุ่มที่ 1 ประกอบไปด้วย MoneyTest
กลุ่มที่ 2 ประกอบไปด้วย MoneyTest2 และ MoneyTest3

คำถาม
ใน jUnit สามารถจัดการกลุ่มการทดสอบได้ไหม ?
คำตอบ
ได้สิ ใช้ Test Suite ไงล่ะ ดังนี้

จากนั้นทำการ run เฉพาะ Group2 หรือ กลุ่มที่ 2
ผลการทำงานเป็นดังนี้
Screen Shot 2558-02-25 at 2.46.13 PM

ดังนั้นในตอนนี้เรามาดูหน่อยว่าทำอะไรไปบ้าง ?

เริ่มเขียน test แรกคือ MoneyTest
เขียน test case แรก คือ simpleAddWithSameCurrency
หลังจากที่ทำการสร้าง method add() ใน class Money

โดยปกติ ในการพัฒนา software นั้น
เราควรพัฒนาด้วยการเขียน test เล็กๆ แบบ step-by-step ไปเรื่อยๆ
เพื่อช่วยลดเวลาในการเขียน test ให้น้อยลง
ทำให้คุณรู้ว่า กำลังพัฒนาอะไร ?
ทำให้คุณรู้ว่า กำลังแก้ไขปัญหาอะไร ?
ทำให้คุณรู้ว่า สิ่งที่คุณกำลังทำมัน work หรือไม่ ?

และได้ทำการ refactor test นั่นคือ ลด code ที่มันซ้ำซ้อน
ด้วยการย้าย test fixture ไปไว้ในส่วนของ setup
เพื่อให้ใช้งานในทุกๆ test case นั่นเอง

สุดท้ายทำการแบ่งกลุ่มของ test ด้วย Test Suite
ทำให้สามารถ run test ในกลุ่มที่ต้องการได้ง่ายและสะดวกขึ้น
ตลอดจน ช่วยทำให้การทดสอบเร็วขึ้นอีกด้วย
แต่อย่าลืมว่า ทุกๆ test จะต้องถูกทดสอบด้วยนะ อย่างน้อยวันละ 1-2 ครั้ง

ในตอนต่อไป
เรามาเขียน code เมื่อมี requirement เพิ่มเติมกันนะครับ …