บันทึกการเรียนรู้ การเขียน Unit Test ให้ Vuejs Application

Supawit R
odds.team
Published in
2 min readJul 1, 2020

สวัสดีครับ เร็ว ๆ นี้ ผมได้มีโอกาสมาเขียน Vuejs จากปกติจะเขียน React ซะเป็นส่วนใหญ่

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

แต่ก่อนจะไปดูกันว่าทดสอบยังไง เราควรจะรู้ก่อนว่าทดสอบไป “ทำไม”

เขียนชุดทดสอบไปทำไมกันนะ ?

การเขียนชุดทดสอบมีเป้าหมายอยู่หลายประเด็นมากเลย แต่หลัก ๆ ก็จะเป็น

  • เพิ่มความมั่นใจ ในการเพิ่มฟีเจอร์ใหม่ ๆ หรือแก้ไขโค้ดที่มีอยู่แล้ว ว่าจะไม่ทำให้ของเดิมพัง จะได้หลับอย่างสบายใจ โปรแกรมไม่พังกลางดึก
  • เพิ่มคุณภาพของโค้ด เพราะหากคิดว่า component ที่เราเขียนจำเป็นต้องทำให้ test ได้ เราจะพยายามแยกของออกจากกัน และทำให้แต่ละส่วนเป็นอิสระ สามารถ reuse ได้
  • มีความเป็นเอกสารที่ดี ผลลัพธ์ที่ได้จากการเขียน test ที่ดี คือ การสร้าง document สำหรับทีม ง่ายต่อการไปพัฒนาต่อ

เราควรทดสอบอะไร ?

เมื่อเรารู้แล้วว่าการเขียน test มีเป้าหมายอะไร และมันมีคุณค่าอย่างไร คำถามถัดไปคือ แล้วเราควร test อะไรกันนะ ?

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

สิ่งที่เราจะทดสอบควรจะเป็น high level ว่า input ที่ส่งไป จะทำให้ output เป็นไปตามความคาดหวังไหม

input เป็นอะไรได้บ้าง

  • Component Data
  • Component Props
  • User Interaction เช่น ผู้ใช้กดปุ่ม
  • Lifecycle Methods เช่น mounted, created
  • Vuex store

แล้วฝั่ง output ละ

  • สิ่งที่ Vuejs render ออกมาจาก component หรือ html DOM
  • การที่ function ถูกเรียก
  • การที่ event ถูกเรียกโดย component
  • การที่ Route (url ของเว็บ) ถูกเปลี่ยน
  • การเปลี่ยนแปลงของ Vuex store
  • Connection with children เช่น การเปลี่ยนแปลงใน child components

สิ่งที่ทดสอบเน้นย้ำว่าคือ input ส่งไปเป็นอะไร จะได้ output กลับมา ไม่ใช่บอกว่าโค้ดมันทำงานอย่างไร

ยกตัวอย่าง: ทดสอบ function บวกเลข โดยการรับ input เป็นตัวเลข 2 ตัว และ output เป็นผลลัพธ์ที่ได้จากการบวก

การทดสอบอาจจะกำหนด input เช่น 1 และ 2 ส่วน output ที่คาดหวังเป็น 3

เนื้อในของ function เราอาจจะเขียนแบบ simple หรืออาจไปใช้ library ก็เป็นได้ ซึ่งไม่ใช่ประเด็นที่จะต้องเขียน test

อะไรที่ไม่ test

มีสามอันจำง่าย ๆ ท.ด.ฟ. (เทสดับไฟ)

  • (ท) Third Party Libraries: เราใช้ library ที่คนอื่นเขียนมา เราก็คาดหวังว่าคนที่เขียน framework นี้จะเขียนทดสอบมาอยู่แล้ว ดังนั้นก็ไม่จำเป็นที่จะ test อะไรที่เขาทดสอบมาแล้ว แล้วถ้าคุณไม่คิดว่าตัว library เขียน test มาดีอยู่แล้ว ก็อย่าไปใช้ตั้งแต่แรกเลย เช่น จะใช้ axios ก็ไม่ต้องทดสอบว่า axios call http อย่างไร
  • (ด) Detail: รายละเอียดที่อยู่ภายใน เพื่อให้เราสามารถยืดหยุ่นการทำงานข้างในให้ดีขึ้นได้ โดยไม่ทำให้ test พัง เช่น วันนึงใน function เราอยากปรับจูนให้ algorithm ในนั้นให้ดีขึ้นก็ถือเป็นการ refactor และ test ไม่ควรพัง
  • (ฟ) Framework: เช่นเดียวกับ Third Party Libraries เราคาดหวังว่าเขาเขียน test มาอยู่แล้ว ไม่จำเป็นต้องทดสอบตัวเฟรมเวิร์ก เช่น การ validate type ของ props ก็ไม่ต้อง test

ทดสอบยังไง

ส่วนสุดท้ายเมื่อเราตอบตัวเองได้แล้วว่า ทำไมถึง test ? อะไรควร/ไม่ควร test ? เราถึงจะมารู้ว่าจะทดสอบยังไง

ตัวอย่างการทดสอบ Vuejs

ทดสอบเรื่องการไม่แสดงผลปุ่ม Logout หากผู้ใช้ยังไม่ได้เข้าสู่ระบบ และทดสอบเรื่องการแสดงปุ่ม Logout หากผู้ใช้เข้าสู่ระบบอยู่

โดยเรามีโค้ด Header.vue ตามที่แสดงด้านล่าง

Header component

โดยปุ่ม Logout จะแสดงตามสถานะของตัวแปร loggedIn หากเป็น falseให้แสดงออกมาทางหน้าจอ หากสถานะเป็น true ให้ซ่อนปุ่มนั้น

Library ที่ใช้

ในตัวอย่างนี้เนื่องจากผู้เขียนถนัด jest จึงใช้ library ตามด้านล่าง

  • @vue/test-utils
  • @vue/cli-plugin-unit-jest

เพิ่มเข้า project โดยใช้คำสั่ง

npm install --save-dev <library-name>
// or
yarn add --dev <library-name>

เริ่มทำการเขียนชุดทดสอบ ตามที่วางแผนไว้ ได้ออกเป็น 2 test cases คือ

  1. ซ่อนปุ่ม logout หากผู้ใช้ ถ้าไม่ได้เข้าสู่ระบบ

2. แสดงปุ่ม logout หากผู้ใช้เข้าสู่ระบบอยู่

โดยผลลัพธ์ออกมาตามโค้ดด้านล่าง

test Header component

อธิบายเพิ่มเติม

mount เป็น function ที่สั่งให้ component นั้น render ออกมา

expect เป็น function ของ jest ที่ไว้ตรวจสอบความคาดหวังของเรา

wrapper.setData เป็น function ที่ไว้เปลี่ยนค่าของ property ใน component นั้น

await wrapper.vm.$nextTick() เป็นการบอกให้ component ทำการ render ใหม่อีกครั้ง หลังจากที่เรามีการเปลี่ยนแปลง property ของ Header component

สามารถเข้าไปดูโค้ดเต็ม ๆ ได้จาก

Special Thanks

ขอขอบคุณ “สำนักงานส่งเสริมเศรษฐกิจดิจิทัล (depa)” และคณาจารย์ “คณะเทคโนโลยีสารสนเทศ มจธ. (SIT)” ที่ให้การสนับสนุน “ทุนเพชรพระจอมเกล้าเพื่อพัฒนาเทคโนโลยีและนวัตกรรมดิจิทัล (KMUTT-depa)” ซึ่งเป็นทุนที่มอบความรู้ ทักษะและโอกาสดีในการฝึกฝนพัฒนาทักษะที่มีอยู่ให้เฉียบคมมากยิ่งขึ้นครับ ❤️

ขอบคุณข้อมูลจาก

https://www.vuemastery.com/courses/unit-testing/what-to-test/

--

--

Supawit R
odds.team

a developer who love to learn, read, and sleep.