Tag Archives: test

มาฟังผมฝอยเรื่อง unit test กัน

ผมเป็นแฟนตัวยงของการเขียน automate test (ต่อไปผมจะย่อสั้นๆ เหลือแค่ test นะครับ) ถึงขั้นใช้เป็นส่วนหนึ่งในการตัดสินใจเลือกเข้าทำงานที่ใดๆ เลยทีเดียว เพราะผมเชื่อว่าการเขียน test อย่างจริงจัง มีประโยชน์มากมาย ทั้งเป็นส่วนหนึ่งที่จะทำให้เราทำงานได้ทันเวลามากขึ้น มีความมั่นใจมากขึ้นเมื่อจะ deploy ขึ้น production แก้ไขปรับปรุงโปรแกรมเราได้อย่างมั่นใจ ว่าไม่ไปทำให้สิ่งที่เคยทำมาพัง …

แต่การเขียน test นั้นไม่ง่ายนัก เพราะมีหลายเรื่องที่ต้องคำนึงถึง หากเขียน test ไม่ดี จะทำให้เสียเวลาการทำงานมากขึ้นโดยเปล่าประโยชน์ และเป็นภาระต่อไปในอนาคต ดังที่ผมได้เคยไปสร้าง bad impression และ code ที่ไม่ค่อยมีประโยชน์เท่าไหร่ไว้ และส่วนตัวผมเคยพยายามเขียนถึงเรื่องการเขียน test ไปแล้วครั้งหนึ่ง แต่รู้สึกว่าทำได้ไม่ดีเท่าไหร่

ช่วงนี้ได้มีโอกาสดูเทปบันทึก RubyConf2011 ถึงมันจะมีตั้ง 65 talk แต่แน่นอน ผมเลือกดูเรื่องเกี่ยวกับ testing เป็นเรื่องแรกๆ

แต่ก่อนที่ผมจะไปเล่าถึงเรื่อง talk ที่ผมได้ดูนั้น อยากจะทำความเค้าใจกันนิดนึง

สำหรับ unit testing ในโลก OOP (test ระดับอื่นไม่เกี่ยวในวันนี้) ปัจจุบันนี้มีสไตล์การเขียนอยู่ 2 แบบ คือ

  1. Interaction testing (mock) คือ การ test message ที่ object ส่งหากัน ด้วยการใช้ mock ไปตรวจสอบการ call method ระหว่าง object อาจจะมองได้ว่าเป็นการทำ white box testing
  2. State testing คือ การเรียก method แล้วตรวจสอบผลลัพธ์ที่ออกมา อาจมองได้ว่าเป็นการทำ black box testing

ใน blog นี้จะกล่าวถึง 2 แบบนี้อยู่เรื่อยๆ นะครับ

Continue reading

Making CHANGE possible

จากความเน่าของโพสเมื่อวานนี้ วันนี้ขอรวบรวมสติใหม่ หลังจากนี้ไปจะใจเย็นๆ พูดถึงทีละเรื่องนะครับ

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

mindset เรื่องการยอมรับความเปลี่ยนแปลง เป็นเรื่องที่ผมรู้สึกว่า ขาด อยู่ในโลกการพัฒนา software ในปัจจุบัน เป็นสาเหตุสำคัญที่ทำให้ชีวิตนักพัฒนา software มัน เศร้า กันอย่างที่เป็นอยู่

ผมจะบอกคุณว่า ถ้าคุณมี mindset เรื่องยอมรับการเปลี่ยนแปลง ชีวิตการพัฒนา software ของคุณจะไม่เหมือนเดิมอีกต่อไป

ผมจะยกตัวอย่างวงจรอุบาตนึงให้ฟัง

กลัวการเปลี่ยนแปลง -> Design อย่างละเอียด จะได้ไม่ต้องแก้ -> ลงมือ code -> งานเสร็จ ไปส่วนหนึ่ง -> แก้ เพราะมี requirement เพิ่ม, design ผิด ทำไม่ได้จริง -> เหนื่อย, เปลืองพลังงาน, เปลืองเวลา(ทั้งตอน design และตอนแก้), งานเลท -> ไม่อยากแก้แล้ว -> กลัวการเปลี่ยนแปลง -> …

ถ้าเราเปลี่ยนความคิดมาตีซี้กับความเปลี่ยนแปลง ทำให้มันเป็นเพื่อนของเรา จะเกิดวงจรใหม่ขึ้น

ชอบการเปลี่ยนแปลง -> Design น้อยๆ พอที่จำเป็น -> ลงมือ code พร้อมเขียน test -> แก้เพราะมี requirement เพิ่ม, ทำเพิ่ม -> test พัง -> แก้ code และแก้ test -> รัน test ผ่านหมด นอนหลับฝันดี -> ชอบการเปลี่ยนแปลง -> …

เรื่องนี้มีประเด็นหนึ่งที่น่าสนใจ คือ ยิ่งคุณเป็นคนที่ design เก่งเท่าไหร่ คุณจะยิ่งเกลียดความเปลี่ยนแปลงเท่านั้น เพราะคุณจะเจอความเปลี่ยนแปลงน้อยกว่าคนอื่น แต่เมื่อมันมาถึงทุกอย่างจะเป็นเรื่องใหญ่โต และคุณจะโทษ design ของคุณ หรือโทษความเปลี่ยนแปลง ที่ทำให้ชีวิตคุณมีปัญหา ความจริงแล้ว ไม่ใช่เลย ความเปลี่ยนแปลง เป็นเรื่องธรรมชาติ ถ้าใครนับถือศาสนาพุทธคงทราบดี เราต้องยอมรับว่ามันมีจริง และหาทางรับมือกับมัน ไม่ใช่พยายามหลีกเลี่ยง

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

คุณรู้หรือไม่ว่าการ design ที่มากเกินไป อาจจะหยุดยั้ง innovation ในโปรเจ็คของคุณ!!! 

แต่ไอ่การจะทำให้การเปลี่ยนแปลงเป็นไปได้โดยง่ายนั้น ก็ไม่ใช่เรื่องง่าย ไม่ใช่ว่านึกอยากทำก็ทำได้ ไม่ใช่เกิดได้ในวันนี้พรุ่งนี้ มีความรู้มากมายที่ต้องใช้ประกอบให้มันเกิดขึ้นได้

  • ความรู้ในเรื่อง design, abstraction และเทคนิคการเขียน code เพื่อให้เกิดสิ่งเหล่านี้ คุณไม่ควร design เป็นจำนวนมากในครั้งเดียว แต่คุณต้องรู้ว่า design ที่ดีเป็นอย่างไร เพื่อที่คุณจะได้ evolve software ของคุณไปได้ถูกทาง
  • Incremental dev & just enough design ทำทีละส่วนเล็กๆ ให้สำเร็จขึ้นมา คิดในส่วนที่กำลังจะทำให้มากๆ ส่วนที่ยังไม่ทำ ไม่ต้องคิด ไม่ต้องทำเผื่อ เพราะเมื่อถึงวันที่เราจะทำทุกอย่างมันเปลี่ยนไปแล้ว ไว้ค่อยมาคิดกันใหม่
  • test & refactoring หลังจากที่คุณทำที่ละส่วนเล็กๆ แล้ว เมื่อคุณจะทำเพิ่ม แน่นอนคุณต้องแก้ของเก่า เพราะคุณไม่ได้คิดเผื่อไว้ คุณต้องมี test เพื่อตรวจจับของเก่าที่พัง และ refactor code หลังจากที่ทำเสร็จ เพื่อให้มันคงความแก้ง่าย เอาไว้
  • clean code ทำให้คุณและเพื่อนร่วมทีมแก้ code ได้ง่ายขึ้น

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

ปล. จริงๆ แล้วเรื่องนี้มันคือ เรื่องเดียวกับ pull system ที่ผมเคยเขียนไป แต่แค่เป็นคนละมุมมองเท่านั้นเองแหละครับ

Intro to fun automate testing

เชื่อว่าทุกคนคงมีความเห็นตรงกัน ว่าการที่โปรแกรมที่เขียนขึ้น จะมีคุณภาพได้นั้น จะต้องผ่านการ test

แต่ test มันมีต้นทุน การจะเขียน test มันต้องลงทุนลงแรง เหนื่อยมากขึ้น เปลืองเวลามากขึ้น จะทำไงดี จะไม่ test ก็คงไม่ได้ (เอ๊ะ หรือว่าได้ อันนี้แล้วแต่มุมมองนะครับ)

สิ่งที่เราพอจะทำได้คือ ทำให้ test มัน สนุกขึ้น เหนื่อยน้อยลง ใช้พลังงานและทรัพยากรน้อยลงในการดูแลมัน

จากข้อต่างๆ ที่กล่าวมานั้นหลีกเลี่ยงไม่ได้ที่เราจะต้องทำการ test แบบ automate ไม่อย่างนั้นคิดง่ายๆ test มือ ซ้ำๆ ที่เดิม 2 รอบก็ไม่สนุกแล้ว

แต่ใช่ว่าแค่การเขียน automate test จะทำให้ชีวิตของเราสวยงามเสมอไป มีสิ่งที่เราต้องระลึกไว้เสมอ เวลาเขียน test เพิ่มเติม นอกเหนือจากเรื่องการตรวจสอบความถูกต้องของโปรแกรม เพื่อให้คงความสนุก และสบายไว้ คือ

  1. ต้องเขียนง่าย
  2. ต้องแก้ง่าย
  3. ต้องสั้น
  4. ต้องอ่านรู้เรื่อง
  5. ต้องรันง่าย
  6. ต้องรันได้เร็ว
  7. ต้องพังในจังหวะที่ควรจะพัง

โดย concept นึงที่ เป็นส่วนหนึ่งที่ทำให้เกิดข้อ 1,2,3,4,6,7 ได้ คือ เรื่อง testability

ลิงค์ต่อไปนี้ คือ ส่วนหนึ่งที่ผมใช้ศึกษาเรื่องนี้

youtube , pdf , youtube2 , youtube3

Concept หลักๆเลย คือ ต้องทำให้เราสามารถ test เฉพาะส่วนที่ต้องการเป็นส่วนๆได้ โดยไม่ต้องไปผูกพันธ์ test ส่วนอื่นไปด้วย จาก link ด้านบน ดึงออกมาเป็น guideline ดังนี้

  1. ใน code ส่วนสร้าง object ใดๆ จะต้องไม่มีโลจิค เพราะว่า ไม่อย่างนั้นในทุกการทดสอบแปลว่าเรา ทดสอบ code ส่วนนั้นด้วยเสมอ ถ้า code ส่วนนั้นพัง test พังหมด ถ้า​ code ส่วนนั้นช้า test ช้าหมด
  2. ใน code ไม่ควรมีการสร้าง object อื่นปะปนอยู่กับโลจิค เพราะว่า เราต้องควบคุมสภาพแวดล้อมรอบ code กลุ่มที่เราจะ test และลดการ test ซ้ำซ้อน ในบางครั้งเราจึงต้องมีการเปลี่ยน object อื่นๆที่เกี่ยวข้องไปอยู่ในสภาพที่เราควบคุมให้มัน return ผลลัพธ์ตามที่ต้องการ, ทำงานได้เร็วขึ้น ตามอ่านได้ที่ Test Double
  3. ใน code จะต้องไม่มีส่วนที่เรียกใช้งาน ไลบรารี global ที่เมื่อเรียกแต่ละครั้งอาจได้ค่ากลับคืนไม่เท่ากัน (Global State) โดยตรง เช่น เวลา, ส่ง e-mail, database สิ่งเหล่านี้มีผลต่อการ test ของเรา เช่น ระบบที่รันเดือนละครั้ง, ส่ง e-mail ทุกคร้ังที่ test, database access ช้า สิ่งเหล่านี้ต้องถูกกำจัดออกไปด้วย Test Double เช่นกัน
  4. ใน code ต้องไม่มีการเรียก property ของ object ที่เกี่ยวภายใน (Violate laws of demeter) เพราะไม่เช่นนั้น เวลาจะเขียน test ทีต้อง setup ยาวมาก
  5. code ส่วนที่ test ต้องไม่ทำอะไรมากเกินไป ไม่อย่างงั้น test จะพังง่าย และอ่านเข้าใจยาก เนื่องจากต้อง test หลายเรื่อง อาจจะทำให้ไม่ชัดเจนว่าจะ test เรื่องใด

ถ้าอยากจะทำสิ่งเหล่านี้ได้โดยอัตโนมัติ ลองศึกษาการทำ TDD แบบถูกวิธีดูครับ มีโพสที่เคยเขียนเรื่อง TDD ไว้หน่อย อันนี้

 

สิ่งที่เขียนมาข้างต้นมีผลกระทบโดยตรงกับภาษาที่เป็น static และ strong typing

สำหรับภาษา dynamic typing บางภาษา ความสามารถในการเปิด class/function ออกมาแก้ไขได้ ทำให้สามารถสร้างสภาพแวดล้อมที่เหมาะสมกับการ test ถึงแม้จะมีการละเมิดข้อด้านบนก็ตาม

ด้านภาษา functional language จะกังวลเรื่องเหล่านี้น้อยหน่อย เพราะเขียนให้ละเมิดสิ่งด้านบนได้ยาก

 

จะเห็นว่าจากเรื่องนี้ สิ่งที่จำเป็นในการทำให้โปรแกรมเราสามารถ test ได้ คือ การมีความเข้าใจในโปรแกรมเป็นอย่างดี และเขียนโปรแกรมนั้น อย่างเหมาะสม จึงเป็นไปไม่ได้ที่ทางฝั่งคนเขียนโปรแกรมจะไม่ลงไปมีส่วนร่วมในการ test ไม่ว่าจะเป็นคนเขียน test เอง หรือร่วมมือกับคนเขียน test อย่างจริงจัง เครดิต

 

เขียนไปเขียนมา รู้สึกว่า organize ไม่ดีเลย และมีรายละเอียดที่ข้ามไปอีกเยอะมาก ไว้นานๆไป มีแรง จะกลับมาเขียนใหม่ลึกๆ แบ่งแยกดีๆ แล้วกันครับ

Happy testing สวัสดีครับ