TDD is not the f*ucking red, green and blue Part 5

Jassadakorn.ket
te<h @TDG
Published in
4 min readJun 20, 2022

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

แต่โชคดีที่ True Digital Group มี

SE (System Engineer) ที่คอยทำ Flow Chart แบบละเอียดมาให้
QA ที่เขียน Test Case มาให้อย่างละเอียดครบทุกเคส
PO ที่เขียน Acceptance Criteria มาชัดๆว่าควรโฟกัสอะไรก่อน
สุดท้ายทีมทำ CI/CD ที่เขียน script ทำให้ test ของเราได้ไปรันก่อนจะ
launch to store

พอมีทีมเหล่านี้คอย support ทีนี้เราก็จะ focus แค่การเขียน test ของเราพอ

  1. มึง…….กูรู้สึกว่างเปล่าเมื่ออยู่ในหน้าจอ test ( 2 สิ่งที่ต้องนึกถึง )
  2. ชิบหายใช้เวลาเยอะมากกว่าจะเขียนได้ 1 case ( ช้าไม่เป็นก็เร็วไม่ได้ )
  3. What the fuck รันกี่ครั้งทำไมแม่งไม่เหมือนเดิม ( 3 สิ่งต้องห้าม )
  4. จะทดสอบอะไร ก็ให้สิ่งนั้นเป็นของจริง ที่เหลือเป็นของเก๊ อย่าใส่ของจริงมาทั้งหมดโว้ยย ( Protocol is Hero )

ความเดิมตอนที่แล้ว เราเรียนรู้วิธีการใช้ spy inject เข้าไปยังสิ่งที่เราจะ test แล้ว

และเราก็พยายามแก้ logic ให้เป็นไปตาม spec ที่บอกเอาไว้ในตอนแรกว่าแสดง 10 อันพอ ถ้า API มา 20 อัน

ทีนี้ก็จะเหลือการ filter expired date ออกไปให้หมด

แต่ก่อนจะไปถึงจุดนั้น ผมขอแนะนำวิธีการเปิด code coverage เพื่อดูว่าเรา test เราครอบคลุมกี่เปอร์เซ็นของโปรเจค

ต่อให้ครอบคลุมทั้งหมดไม่ได้แปลว่าไม่มี bug ( Counter Test )

จากภาพด้านบนกดไปที่ชื่อ scheme ในที่นี้คือ Product จากนั้น Edit Scheme

จากภาพด้านบน เลือกไปที่ Test -> Options -> Code Coverage

ติ๊กถูกที่ Gather coverage for some targets แล้วเลือกไปที่ Target Product จากนั้นปิดหน้าต่างลงแล้วไปลองกัน

หลังจากลอง run test เสร็จเราจะกดไปที่ menu นี้

เลือกที่ Coverage

ก็จะเห็นได้ว่ามันขึ้นแค่ 50% เองทำไมไม่ 100% นะไปดูกัน

ก็เพราะว่าเรายังไม่ได้ย้าย class และ protocol ที่ไม่เกี่ยวข้องออกจาก viewModel สังเกตุทางขวาจะมีสีน้ำตาลเพื่อบอกว่า test ยังไม่ cover ถ้า cover แล้วจะเป็นสีเทา

หลังจากเราย้าย code ที่ไม่เกี่ยวข้องออกไปแล้ว ทีนี้ logic ของเราก็ cover 100% แต่ แต่ logic ของเราก็ยังไม่ครบนี่ ยังขาดการ filter expired

จากประสบการณ์ของผมการทำ TDD นั้น การดู Coverage ไม่ค่อยช่วยอะไรเท่าไหร่
เพราะเราเขียน test ก่อนแล้วค่อย implement code มันก็ต้อง 100% อยู่แล้วปะ
ถ้ามันต่ำกว่านั้นมากๆแสดงว่า แอบเขียน code ก่อนแล้วค่อยเขียน test อ่ะดิ

Coverage100% != No bugs

จากนั้นเราก็มาต่อกันที่เราค้างไว้ในหลาย part เรื่องวันหมดอายุ
จำ part ที่แล้วเรื่อง dependency ได้มั้ยว่าเราต้องเอามันออกไปก่อนเพราะเราไม่สามารถควบคุมค่ามันได้ในตัวอย่างนี้คือ Date() หรือวันที่ปัจจุบัน
ซึ่งมันจะดึงจากเวลาเครื่องเสมอ
แต่เราจะไม่เอา เราจะกำหนดเองเพื่อให้ควบคุมค่าได้ไม่เกิดความคลาดเคลื่อนเวลารันหลายๆรอบ

คำอธิบายภาพด้านบน

  1. กำหนดให้ nowDate เป็นแบบ function ที่ return date เพื่อที่ให้มันถูก compute ใหม่เสมอ และสมมุติว่าถ้า nowDate เป็นวันอาทิตย์ ของที่หมดอายุไปแล้วก็ต้องเป็นวันเสาร์ ส่วนของที่ยังไม่หมดอายุก็เป็นวันจันทร์
  2. set date ที่ยังไม่หมดอายุลงไปใน product
  3. create productList ด้วย expiredDate จากนั้นเอาใส่ใน index 0 , 1 เพื่อให้แน่ใจว่าเมื่อเวลาเราใช้ function array.prefix(10) แล้วจะไม่ถูกตัดออกไปก่อน filter date
  4. เราก็ทำการออกแบบว่าจะ inject nowDate ผ่านเข้าทาง initial นะ

ส่วนฝั่ง production code เราก็ implement logic ตามนี้ซึ่ง

  1. ถ้าไม่ทำ TDD จะต้องรันแอพกี่ครั้ง จะต้องผ่านหน้าต่างๆมากี่หน้า กดปุ่มกี่ปุ่ม จนมาถึง logic ตรงนี้ได้
  2. ใช้ TDD เราแค่กด command + U ก็จบแล้วรู้ผลไว แก้ไขได้เรื่อยๆ

อ่ะลอง commmand + U ผลก็คือผ่านดิ

แต่เราจะเชื่อผลของการ run test ครั้งนี้ได้ยังไงนะ
จากประสบการณ์ของผมแล้ว ผมใช้วิธี Counter test หมายถึง
เขียน test case ขึ้นมาใหม่อีกอันนึง และเจาะจง พุ่งเป้าให้ result
ที่เรา expect ให้มีผลตรงข้ามกันกับ case ที่แล้ว หน้าตามันเป็นยังไง อ่าา ไปดูกัน

ใน case ที่แล้วเรา set product ที่ยังไม่หมดอายุ 20 อัน
ใน case นี้ก็เลย set หมดอายุทั้งหมด 20 อันไปเลย
แล้วมาดูผลกันว่า product list จะเหลือ 0 มั้ย

ผ่านแล้วโว้ยยยยยยยยย

ขอสรุปเลยละกันว่า

  1. Team ต้องช่วย support อย่างมากถ้าจะให้การทำ TDD มีประสิทธิภาพ ( True Digital Group มีครบนะ )
  2. Coverage ไม่ได้ช่วยห่าอะไรให้ Manager ดูไปเท่านั้น
  3. Counter Test เคสที่เพิ่งเขียวไปอยู่เสมอ เพื่อความแน่ใจ

--

--