แนวคิดพื้นฐาน การเขียนเทสเคส Unit Testing

ความสุขของคนที่สร้างซอฟต์แวร์คือ การเห็นคนที่มาใช้ผลงานของเราแล้วได้ประโยชน์และมีความสุขที่จะใช้มันต่อไป

ส่วนตัวเองเคยเป็นนักปั้นโค๊ดที่พอไปวัดไปวาได้ และ  feedback ลูกค้าส่วนหนึ่งบอกว่าชอบและตอบโจทย์ในการแก้ปัญหาให้กับเค้าได้ แต่….พอใช้ไปซักระยะมักกลับมาพร้อมกับบอกว่า “ทำไมตรงนี้มันทำงานอย่างงั้น อย่างงี้”

บางอันนี่ก็เป็นเรื่องของ UX บ้างที่ไม่สื่อความหมายชัดเจน ทำให้ใช้งานยาก

บางอันก็เป็นสิ่งที่ไม่มีใครคาดว่าต้องการให้มันทำงานแบบนั้น (ใช่ครับ แม้แต่ลูกค้าเองก็พึ่งรู้)

บางอันก็เป็นของแถมที่โปรแกรมเมอร์แถมให้ที่ไม่ใช่ทั้ง UX และ ฟีเจอร์ ของแถมที่ว่านี้คือ แมลง (Bug) นั่นเอง

พอเจอบั๊กหัวหน้ามักบอกว่าให้ทำ Unit Testing เพื่อกันบั๊กไม่ให้มันเกิดขึ้นอีก ซึ่งถ้ามองผิวเผินดูเหมือนสมเหตุสมผล แต่ จริงๆแล้วถ้าคนที่ได้เขียน  Unit Testing ไปเรื่อยๆจะรู้ว่า การเขียน Unit Testing ไม่ใช่การหาบั๊ก หรือว่าป้องกันบั๊กทั้งนั้น (อย่าพึ่งงง)

หากแต่มันคือการทำให้ Developer ได้มีโอกาสคิดถึงดีไซน์ของโค๊ดตัวเองตะหาก

การทำ Unit Testing ความหมายที่แท้จริงคือการแบ่งโค๊ดให้ย่อยเป็นส่วนๆที่สามารถที่จะสร้างสภาวะแวดล้อมของส่วนย่อยๆนั้นให้เป็นไปอย่างที่เราต้องการ เพื่อทดสอบ กระบวณการทำงานของโค๊ดส่วนย่อยๆนั้น

ฉะนั้นการดีไซน์เทสเคสให้กับ Unit Testing เลยควรตั้งอยู่บนพื้นฐานที่จะย่อยโค๊ดของเราให้เป็นหน่วยย่อยที่สุดเพื่อให้เราเกิดความมั่นใจว่าโค๊ดของเราทำงานอย่างที่เราตั้งใจให้มันทำงาน โดยที่ไม่ต้องไปต่อ  Database, ฟังชั่นอื่น, และต้องสามารถรันได้รวดเร็วในเวลาไม่เกินวินาที (ใช่ครับ วิเดียวนี่แหล่ะ) ความผิดพลาดส่วนใหญ่คือคนมักสับสันระหว่าง Integration Test กับ Unit Test เลยพากันเขียน Unit Test Case แบบออกทะเล แล้วก็อ้างว่าเขียนแล้ว รันไม่ได้บ้างหล่ะ คิดยากบ้างล่ะ image

ตัวอย่างเช่น

MyFunction (x, y){

ผลลัพธ์ = <Business Logic ที่ใช้ค่า>

Return <ผลลัพธ์จาก Business Logic>

}

MyFunction อาจมี Unit เทสเคสง่ายๆดังนี้

1.  MyFunction ได้รับ ค่าทั้ง  x และ  y  หรือเปล่า ถ้าได้ไม่ครบหรือว่าเกินผลลัพธ์เป็นยังไง

2. ประเภทของ ค่า x, y เป็นไปอย่างที่เราคาดหวังไว้หรือเปล่าเช่น ถ้า มันเป็นตัวเลข เราได้ตั้งค่าสูงสุด หรือค่าตำ่สุดที่สามารถรับได้สำหรับงานของเราหรือเปล่า หรือ ถ้าเกิดว่าเป็น String หรือว่า Text เราได้กำหนดความยาวของ String ไว้หรือเปล่า

3. ถ้าเกิดว่าเราใส่ค่าที่ไม่ตรงกับสิ่งที่เราต้องการ โค๊ดเราได้มีฟ้องว่า ค่าผิดหรือเปล่า (หลายคนบอกว่าหลายๆภาษาได้ทำเรื่องนี้ไว้แล้ว แต่โดยส่วนตัวเชื่อว่า error ที่เราควบคุมได้ย่อมดีกว่า error ที่เราควบคุมไม่ได้)

4. แบ่งประเภทของข้อมูลที่ใช้ในการหาผลลัพธ์ เพื่อให้มั่นใจว่าข้อมูลทุกประเภทที่เข้ามาให้ผลลัพธ์อย่างที่เราต้องการ

5. MyFunction ของเราได้ส่งค่าคืนอย่างที่เราตั้งใจหรือเปล่า

6. ถ้า  MyFunction ต้องมีการ save  ข้อมูลลง   database  เราต้องมีการทำเทสโดยการจำลองสถานการณ์ที่อาจเกิดขึ้นทั้งหมดเพื่อเราจะได้ ดักจับ ปัญหาให้ได้หมด (ฉะนั้นข้อนี้ไม่ควรจะต่อ  Database  โดยตรง เราจำเป็นต้อง mock หรือว่า fake ข้อมูลเพื่อจำลองสถานการณ์)

7. เวลาเขียนต้องเขียนคลุมทั้ง Unhappy Path  และ Happy Path

….เป็นต้น

ดังนั้นถ้าเรารู้ว่า การทำ Unit Testing คือการดีไซน์แล้ว เราก็จะรู้ว่าเราควรจะดีไซน์โค๊ดของเราให้เหมาะกับการใช้งานนั้นๆ ไม่กว้างเกินไป เพราะว่าถ้ากว้างเกินไปเราอาจต้องทำเทสเคสที่ไม่เกี่ยวข้องกับลูกค้าต้องการเลยก็เป็นได้ ฉะนั้น ความพอดีเป็นสิ่งสำคัญ

โดยส่วนตัว ถ้าทีมไม่ได้เขียนเทสก่อนเขียนโค๊ด จะพยายามไม่บังคับให้ทีมทำให้ ครอบคลุม 100%  แต่ให้ทำเพิ่มทุกครั้งที่แตะโค๊ดส่วนนั้น (โดยเฉพาะโค๊ดเก่า)

ข้อควรระวังที่สำคัญ เวลาทำ Unit Test อีกอย่างคือ อย่าทำ Unit Test  กับ Configurations

โดยหลักการแล้ว ค่า configs ไม่ได้เป็นส่วนหนึ่งของ โค๊ด (ไม่อย่างนั้นเราจะแยกมันออกไปทำไม ห๊า) บางคนสนุกบอกว่าก็เขียนได้นี่นา แต่แท้จริงแล้วเป็นเพียงแค่การวางค่า  configs ไว้อีกที่เท่านั้นเอง (แล้วก็บ่นในใจว่า เรากำลังทำการทำสอบ copy and paste สำเร็จ)

อยากรู้เพิ่มเติม ไปดู youtube ( ภาษาอังกฤษ)

 

 

Posted in Coaching, Test

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: