ปัจจุบันการเขียน Automated test นั้นเริ่มมีการนำมาใช้งานพอสมควร
และอาจจะถูกนำมาใช้งานมากขึ้นต่อไป
เนื่องจากประโยชน์ที่ได้รับ ง่ายต่อการเรียนรู้ มันมีมากมาย
โดยเครื่องมือที่ผมมักแนะนำให้ใช้ ก็คือ Robot framework
แต่ในการเขียน Automated test นั้นมักจะเขียนเพียงแค่ให้มันทำงานได้ (Make it Work/Run)
โดยไม่สนใจว่ามันอ่านง่าย ทำความเข้าใจง่ายหรือไม่
ส่งผลให้การดูแลรักษายากมากๆ หรืออาจจะเปลี่ยนแปลงบ่อยๆ
ดังนั้น ขอแนะนำ Tip และ แนวคิดต่างๆ เพื่อปรับปรุงให้ดีขึ้น ดังนี้
Write specifications, not scripts
ให้ทำการซ่อนการกระทำ หรือ การทำงานต่างๆ ไว้
เพราะว่า Automated Test นั้น เราต้องการเขียนให้มันเป็น
Specification ไม่ใช่ Script
เพื่อต้องการให้มันเป็นเอกสารที่มีชีวิต สามารถทำงานได้เอง
รวมทั้งให้ได้เอกสารที่อ่าน และ ทำความเข้าใจได้ง่าย
ตัวอย่าง Script ที่เขียนใน Automated test
Clear database Load database from "sample-data.sql" Start webserver Open URL: http://localhost:8080/myapp Enter username: admin Enter password: admin1 Click the "Login" button Click the "User Administration" link Click the "Create User" button: Enter name: John Smith Enter username: john Enter password: john99 Click the "OK" button Click the "Logout" link Enter username: john Enter password: john99 Click the "Login" button Check page contains text: Hello John!
คำอธิบาย
จะพบว่าใน script ข้างบนนั้น มีพฤติกรรมการทำงานที่ต้องการทดสอบอยู่
แต่มันยากต่อการทำความเข้าใจ เมื่อเห็นครั้งแรก
เนื่องจากมีรายละเอียดต่างๆ มากมาย
รวมทั้ง มีขั้นตอนที่ซ้ำๆ กันพอสมควร ทั้งการ Click, Enter
แสดงว่าสิ่งที่เขียนขึ้นมา มันน่าจะแปลกๆ นะ
ลองคิดดูว่า ถ้ามีการเปลี่ยนแปลงขั้นตอนการทำงาน หรือ เพิ่มเข้าไป
จะต้องทำการเปลี่ยนแปลง Script อีก
มันไม่น่าจะเป็นแนวทางในการเขียนที่ดีนะ !!!
คำถาม
แล้วจะเขียนแบบไหนดีล่ะ ?
คำตอบ
เขียน Specification เพื่ออธิบายพฤติกรรมการทำงาน หรือ สิ่งที่ต้องการทดสอบไปเลย
ตัวอย่างเช่น
When John logs in, a greeting "Hello John!" is displayed.
เป็นการเขียนในระดับที่เรียกว่า Abstraction
โดยไม่ลงรายละเอียดของการทำงานภายใน
แต่สนใจเพียงว่า เราต้องการทดสอบอะไร และจะต้องให้ผลอย่างไรเท่านั้นเอง
ทำให้ถ้ามีการเปลี่ยนแปลงของ requirement เราจะไม่มาแก้ไขในส่วน Abstraction นี้
ดังนั้น Specification นั้นควรที่จะเสถียร เปลี่ยนแปลงน้อยที่สุด
แสดงดังรูป
จากรูป
ในส่วนของ Specification นั้น คือ ส่วนที่เราต้องการทดสอบจริงๆ ซึ่งไม่ควรแกไขบ่อยๆ
ในส่วนของ Fixture คือ ขั้นตอนการทำงานจริงๆ ที่เกิดขึ้น ซึ่งอาจจะเป็น code ในภาษาโปรแกรมต่างๆ
รวมกับข้อมูลที่ใช้ในการทดสอบ
ดังนั้น พยายามแยกกันให้ออก และ ให้ชัด
ในส่วนของ Fixture นั้น เมื่อเราเขียนไปเรื่อยๆ
จะพบว่ามีส่วนที่ซ้ำกันจำนวนมาก ทำให้เราต้องการ refactoring เพื่อลดความซ้ำซ้อนลงไป
เมื่อพัฒนาไปเรื่อยๆ จึงทำให้เกิดสิ่งที่มักใช้ซ้ากันบ่อยๆ
ทำให้เกิดภาษาเฉพาะทางขึ้นมา เรียกว่า DSL (Domain Specific Language)
ทำให้ Fixture นั้นมันเสถียรมากยิ่งขึ้น
ดังนั้นสิ่งที่ผมขอเน้นก็คือ
ในแต่ละ test case ของ Automated test ควรแยกกันให้ชัดเจน
แต่ละ test case ควรที่จะอธิบายพฤติกรรมของระบบ ไม่ใช่ขั้นตอนและรายละเอียด
แต่ละ test case ควรแยกออกจากกัน ไม่ควร dependency กัน
ตัวอย่างเช่น
ในการค้นหาข้อมูล สามารถแยกการค้นหาข้อมูลได้หลายแบบ
- ค้นหาแบบ case-insensitive
- ค้นหาข้อมูลด้วยวันที่
- ค้นหาข้อมูลด้วยรหัส
ในการค้นหาควรที่จะต้องอธิบายว่า ผลการค้นหาเป็นอย่างไรไปเลย
คำถาม
แต่ถ้าต้องการทดสอบการค้นหาในรูปแบบต่างๆ ร่วมกันล่ะ ต้องทำอย่างไร ?
คำตอบ
ให้ทำการเขียน test case หรือ specification ใหม่ขึ้นมา เพื่ออธิบายการทดสอบร่วมกัน
แต่บางคนบอกว่า
เรามา test case ในการค้นหาแต่ละแบบอยู่แล้วนะ จะเขียนใหม่ทำไมล่ะ ?
นั่นแสดงว่า คุณกำลังสร้างการทดสอบที่มีความซับซ้อนขึ้นมาแล้วนะ !!
ดังนั้น เราต้องพิจารณาด้วยเช่นกัน ระหว่างความซ้ำซ้อน กับ ความซับซ้อน
ส่วนตัวผมเรื่อง ความซ้ำซ้อน (Duplication) เพราะว่า
ไม่ต้องการให้ test case มีความซับซ้อนนั่นเอง
ซึ่งตอบโจทย์เรื่อง test case ต้องอ่าน และ เข้าใจได้ง่าย
มาดูสิ่งผิดปกติ จากการเขียน Automated test กันหน่อย
ถ้าคุณมีอาการดังต่อไปนี้ แสดงว่าได้เวลาที่ต้องปรับปรุงแล้วนะครับ
1. ต้องทำการแก้ไข test case หรือ Specification เดิมบ่อยๆ
ของใหม่ก็ต้องสร้างขึ้นมาใหม่
ของเก่ายังต้องมานั่งแก้ไข
งานงอกกันเลยดีเดียว
2 ใน test case มีการใช้คำสั่ง หรือ DSL ที่มีมาให้อยู่แล้ว จำนวนมาก
ถ้าพบเจออาการแบบนี้มากๆ แสดงว่าคุณกำลังเขียน Script ไม่ใช่ Specification นะครับ
ดังนั้นต้อง ลด ละ เลิก ได้เลย
3. ในแต่ละ test case มีการทดสอบจำนวนมาก หรือมีขั้นตอนเยอะไปหมด
ถ้าพบเจอแบบนี้ แนะนำให้พยายามแยกออกเป็น test case เล็กๆ
แต่ test case ต้องเป็นการอธิบายพฤติกรรมของระบบที่ต้องการทดสอบนะ
4. มีการใช้ข้อมูลตัวอย่างซ้ำๆ ใน test case ที่มีโครงสร้างการทำงานคล้ายกัน
ให้ระวังเขียน test case โดยเน้นไปที่ Example data หรือ ข้อมูลตัวอย่าง
เราอาจจะบอกว่า การทดสอบมันควรที่จะอยู่ในรูปทั่วไป
ซึ่งสามารถ reuse ได้สิ
ตัวอย่างเช่น การ login เข้าระบบ สามารถทำการทดสอบได้ 2 กลุ่ม คือ
- Login สำเร็จ
- Login ไม่สำเร็จ
ถ้าเราสนใจที่ข้อมูลตัวอย่าง มักจะเขียนในรูปแบบดังนี้
Username Password Expected Result
somkiat 1234 Pass
pui 1234 Failure
<empty> 1234 Failure
จากการเขียนในรูปแบบนี้ เราพยายามทำให้ test case เดียว ทำงานได้ทุกอย่าง ( One size fits all )
ซึ่งมันเป็นไปไม่ได้ แถมยังเป็นการทำลายเป้าหมายที่เราต้องการตั้งแต่ต้นอีกด้วย
ดังนั้น ควรเขียนในรูปแบบของ Specification เพื่ออธิบายการทดสอบ ดังนี้
- เมื่อผู้ใช้งานทำการ login สำเร็จแล้ว ระบบงานต้องแสดง Pass
- ผู้ใช้งานทำการ login ไ่ม่สำเร็จแล้ว ระบบงานต้องแสดง Pass
หรือ ทำการแยก test case สำหรับการ login สำเร็จ และ ไม่สำเร็จ ออกจากกัน เป็นต้น
ดังนั้น ลองกลับไปดูว่า test case ที่เราเขียนมันอยู่ในรูปแบบไหน
แล้วลองทำการปรัปรุงให้มันดูดีขึ้นอยู่เรื่อยๆ ครับ
Reference Websites
http://concordion.org/Technique.html