Unit test ตอนที่ 1 เรื่องที่ดูเหมือนง่าย แต่ทำยาก

เรื่องที่ดูเหมือนง่าย แต่ทำยาก

Unit test คืออะไร

ผมเขียนเกี่ยวกับ Unit test ไว้ 4 ตอน คุณสามารถกด Link ด้านล่างเพื่ออ่านที่เกี่ยวกับ Unit test ตอนต่างๆได้เลย

คำว่า Unit test นั้นผมได้รู้จักตอนเรียนปี 4 ในวิชา Object Oriented Analysis and Design (จริงๆเป็นวิชาของปี 3 หลักสูตรใหม่ ผมเรียนหลักสูตรเก่าเลยไปลงเรียนกับน้อง) เพราะอาจารย์ให้เขียน App และต้องส่ง Unit test ไปให้ด้วย ตอนนั้นก็งงๆว่ามันคืออะไร ทำไมต้องเขียน ก็เข้าใจคร่าวๆว่ามันเป็นการ Test Code ของเราว่าทำงานถูกต้องไหม ซึ่งตอนเรียนในส่วนนี้พูดถึงหลายอย่างมากไม่ว่าจะ Mock, Stub, Spy และอีกหลายๆอย่างเลย

นิยามแบบทางการผมแนะนำให้ตามไปอ่านที่ wiki หรือ อ่านจากของนักพัฒนาท่านอื่นซึ่งมีมากมายเช่น ของคุณ Tanapol Nearunchorn หรือ ของคุณ Minseo Chayabanjonglerd ซึ่งอธิบายไว้แล้ว แต่สำหรับผมโปรแกรมเมอร์บ้านๆมันคือ “การเขียน Code ไว้ Test Code ส่วนหนึ่งว่ามันทำงานถูกต้องตามที่ต้องการหรือไม่ โดยไม่ต้องติดต่อกับส่วนจริงๆที่เกี่ยวข้องกับ Code ส่วนนั้น” อ่านแล้วงงสินะ ผมเลยแนะนำให้อ่านของคนอื่นไงล่ะ

เข้าส่วนการอธิบาย

Code ส่วนหนึ่ง

ความหมายคือ Function , Control Flow, Class หรือส่วนหนึ่งส่วนหนึ่งของ Code ก็ได้

โดยไม่ต้องติดต่อกับส่วนจริงๆที่เกี่ยวข้องกับ Code ส่วนนั้น

ความหมายคือ อ่า อธิบายยากละ คือ โดยปกติเวลาเราพัฒนาโปรแกรมที่เริ่มซับซ้อนเนี่ยมันจะไม่ทำงานได้โดย Code เพียงส่วนเดียว ยกตัวอย่างง่ายๆอย่าง Web application ที่ต้องมี ส่วน Presentations ส่วน Business Logic ส่วนติดต่อ Database (อันนี้ผมแบ่งแบบคร่าวๆไม่ได้ยึดหลักอะไรเลย) จะเห็นว่ามีส่วนที่เกี่ยวข้องกันคือ ส่วน Business Logic เกี่ยวข้องกับส่วน Database ดังนั้น ถ้าผมจะทำการเขียน Unit test code ส่วนหนึ่งที่เรียกว่า Business Logic ผมจะต้องเขียน Unit test โดยไม่ต้องติดต่อกับส่วน Database ตัวจริง

อะไรวะ

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

ทำไมต้องทำ ทำแล้วได้อะไร

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

ทำเพื่อให้เรามั่นใจว่า Code ที่เราเขียนนั้นทำงานถูกต้อง

อันนี้กำปั้นทุบดินมาก เขียน Test ก็เพื่อไว้เช็คว่า Code ทำงานถูกไหม

ทำเพื่อให้เราสามารถ Refactor code ได้

อันนี้เป็นเรื่องที่หลายคน หลายองค์กร หลายบริษัท เพิกเฉยหรือถึงกับบอกว่าไร้สาระมากๆ คือมันจะมีคำพูดคำพูดนึงบอกว่า “จะไปแก้ Code ที่ทำงานได้แล้วทำไม” หรือ “แก้แล้วรายได้บริษัทเพิ่มไหม มีแต่เพิ่ม Cost” ผมทำงานมาประมาณ 3 ปี (ณ เวลานี้) ได้ยินคำพูดนี้บ่อยมาก บ่อยจนเบื่อ คือในทางธุรกิจการ Refactor code มันไม่ได้เพิ่มรายได้หรอกครับ

แต่ในทาง Technical มันเป็นการช่วยลด Cost ที่ต้องมาอ่าน Code ทำความเข้าใจ Code ถ้าเปรียบง่ายๆคือ ระหว่างโกดังที่ของจัดระเบียบเรียบร้อยมีการจัดหมวดหมู่สินค้าต่างๆ กับ โกดังที่สักแต่ว่าเก็บห่าอะไรเข้าไป ใส่ส่งๆใส่เร็วๆ คุณคิดว่าถ้าวันนึงต้องเอารูปน้องเฌอปราง น้องแนทเธอรีน มาชื่นชมความงาม โกดังไหนจะหาของเจอก่อนกัน ถ้าพูดกันตามทฤษฎี อะไรที่ถูกเก็บเป็นระเบียบย่อมถูกหาได้เร็วกว่าอะไรที่เก็บแบบมั่วๆซั่วๆ (นึกภาพการหาข้อมูลใน Array กับ การหาข้อมูล AVL Tree) เช่นกัน ถ้า Code ที่ทำการ Refactor ให้อ่านง่าย เป็นระเบียบ มันย่อมทำความเข้าใจง่ายกว่า Code เหี้ยๆที่เขียนแบบชุ่ยๆ
แต่อย่างว่าบริษัทหรือองค์กรส่วนใหญ่มักจะสนใจแต่รายได้และด้วยความที่ไม่เขาไม่ได้เข้าใจเนื้องานจริงๆของการ Develop เขาจะไม่เคยเห็น Cost แฝงพวกนี้ มันเป็นเรื่องยากที่จะพูดให้เข้าใจและสุดท้ายมันรำคาญมากจนไม่อยากจะพูดให้เข้าใจ

คำถามต่อไปแล้วมี Unit test แล้วมันทำให้ Refactor ได้ยังไง คำถามเวลาที่เราจะแก้ Code จะมีคือ “จะมั่นใจได้ไงว่า Code ที่แก้ทำงานถูกต้อง” บอกเลยว่าเป็นคำถาม Classic (ยังกะเพลง Canon) คำตอบมันก็มีมากมายเลย เช่น เชื่อมือผม , ผม Test แล้ว, เอาหัวเป็นประกัน แต่คำคอบของคำถามนี้จริงๆมันคือ “ต้อง Test โว้ย” ซึ่งถ้าคุณต้อง Test เอง คุณต้อง Test ทุก Case ของส่วนที่คุณแก้ ถ้าส่วนนี้มี 100 Case แล้ว Manual Test ก็ “ขอให้โชคดี ขอให้มีสุข” แต่ถ้าคุณเขียน Unit test คุณจะแค่สั่ง Run แล้วมัน Test ทุก Case ให้คุณ คุณจะไม่กลัวการ Refactor code เพราะถ้า Refactor แล้วมีอะไรหลุด คุณจะทราบจาก Unit test

ทำแล้วคุณจะได้คิดก่อนเขียน คุณจะเห็นกรณีที่คุณมองข้ามไป

การเขียน Unit test มันจะเป็นการบีบบังคับให้คุณคิดก่อนที่เขียน เพราะตามหลักการเขียน Unit test คุณต้องเขียน Unit test ก่อนที่จะเขียน Code ดังนั้นคุณจะต้องคิด คิด คิด แล้วก็คิด ว่ามันจะมี Case อะไรบ้าง เช่น ถ้าคุณเขียนส่วน Business Logic เกี่ยวกับการกรองข้อมูลลูกค้าออกกลุ่มๆตามเงื่อนไข คุณก็จะเริ่มคิดว่า Input มันมีอะไรได้บ้าง ถ้าใส่ค่าว่างจะเป็นยังไง มันต้อง Return อะไร ถ้าส่ง Null ล่ะ ถ้าส่งค่าที่ไม่มีใน Master File ล่ะ ถ้า … มันจะค่อยๆเข้ามาเวลาคิด เพราะเราเปลี่ยนความคิดจาก เราเขียน Code ให้เสร็จ มาเป็นคิดว่า Code ที่เราจะเขียนมี Input อะไร Output อะไร เราจะเห็นภาพรวม เราจะเห็นจุดที่ควรระวัง จุดที่มีปัญหาเกี่ยวกับ Design แล้วไปคุยกับทีม ซึ่งเสียเวลาน้อยกว่า การเขียน Code ไปครึ่งทางแล้ว “ฉิบหาย มันมี Case นี้ดวยว่ะ แล้วจะเอาข้อมูลมาจากไหนวะ” หรือ อ้าว ตรงนี้มันใช้วิธีนี้ไม่ได้ ต้องแก้ใหม่หมด

ทำแล้วคุณจะได้ Code ที่ยืดหยุ่นระดับหนึ่ง

เมื่อคุณต้องเขียน Unit test คุณจะเจอกับคำว่า โดยไม่ต้องติดต่อกับส่วนจริงๆที่เกี่ยวข้องกับ Code ส่วนนั้น ไอตัวนี้แหละที่เป็นข้อบังคับทำให้เราต้องเขียน Code เพื่อให้เอื้ออำนวยในการทำแบบนี้ (วิธีไหนเดี๋ยวอธิบายอื่นละกัน เดี๋ยวจะยาวกว่านี้ ซึ่งตอนนี้ก็น่าจะอ่านจนเบื่อละ) ซึ่งถ้าทำตามนั้น Code ของคุณจะยืดหยุ่นขึ้นมาระดับหนึ่งเลยล่ะ

ปัญหาที่ต้องเจอ

เวลาที่เพิ่มขึ้น

มันเป็นเรื่องปกติมากที่เวลาจะต้องเพิ่มขึ้น ก็ถ้าคุณเพิ่มจากการวิ่งรอบสนาม 1 รอบมาเป็นวิ่งรอบสนาม 2 รอบ คุณคิดว่าจะใช้เวลามากขึ้นไหมซึ่งถ้าคุณไม่ใช่ The Flash ที่ระยะทาง 800 เมตร กับ 400 เมตรนั้นใช้เวลาห่างกันไม่เกิน ns คุณคงตอบว่าต่างแน่นอน พอเวลาเพิ่มขึ้นมันก็หมายถึง Cost ที่เพิ่มขึ้น ซึ่งบริษัท องค์กร ส่วนใหญ่คงจะไม่ค่อย OK สักเท่าไหร่ นี่เป็นกำแพงด่านแรกๆที่คุณจะต้องเจอ วิธีเอาชนะกำแพงพวกนี้ก็คงจะต้องบอกว่ามันจะลด Cost ในอนาคต ลดความเสี่ยง ซึ่งผมไม่เคยข้ามกำแพงห่านี่ได้เลย เลยต้องเพิ่มเวลาเข้าไป (ทำโอฟรี) เพื่อเพิ่ม Unit test เข้าไปในงานของตัวเอง

มารในใจ

ผมว่าทุกคนจะต้องเจอมารในใจแน่นอนครับ การเขียน Unit test บางครั้งมันก็เป็นอะไรที่น่าเบื่อ เซ็ง เอาเสียมากๆ (เดี๋ยวพอได้ลองเขียนจะรู้เอง) จนบางทีมันแบบ “โอ้ย ทำไมต้องมาเขียนอะไรแบบนี้ด้วยวะ” ดังนั้นหลายคน หลายท่าน ก็จะยอมแพ้และเลิกเขียนมันไป ผมแนะนำว่าก็อดทนเขียนไปเถอะครับ มันเป็นการลงทุนระยะยาว ตัวคุณในอีก 7 วัน 1 เดือน 1 ปี ข้างหน้า หรือ คนอื่นที่มาทำงานต่อ อาจจะขอบคุณคุณก็ได้

เขียนไม่เป็นโว้ย

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

เนื่องด้วยเหตุผลในข้อนี้ ผมเลยอยากจะเขียนแชร์ว่าเขียน Unit test ที่ผมเคยเขียนในงานเนี่ยมันเขียนยังไง ซึ่งอาจจะไม่ใช่ Unit test ที่ดีเลิศหรืออะไร แต่มันคงพอเป็นแนวทางให้คนอื่นๆอ่านแล้วไปลองทำตามได้

Unit test ไม่ใช่ยาวิเศษ ไม่ใช่กระสุนเงินฆ่าปิศาจ ไม่ใช่รักแท้ที่เยียวยาทุกสิ่ง

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

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

เพลงประกอบการเขียนบทความนี้

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

ref :
https://life.wongnai.com/%E0%B9%81%E0%B8%99%E0%B8%A7%E0%B8%84%E0%B8%B4%E0%B8%94%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99-unit-test-b5f89ef871b0
https://medium.com/fungjai/%E0%B8%A1%E0%B8%B2%E0%B8%97%E0%B8%B3%E0%B8%84%E0%B8%A7%E0%B8%B2%E0%B8%A1%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81-unit-test-%E0%B8%AA%E0%B8%B3%E0%B8%AB%E0%B8%A3%E0%B8%B1%E0%B8%9A-android-developer-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-817ac642b44c
https://www.dccomics.com/characters/the-flash
https://www.facebook.com/bnk48official.cherprang/
https://www.facebook.com/bnk48official.natherine/
https://th.wikipedia.org/wiki/%E0%B9%82%E0%B8%94%E0%B8%A3%E0%B8%B2%E0%B9%80%E0%B8%AD%E0%B8%A1%E0%B8%AD%E0%B8%99
https://pixabay.com/