Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

หาจุดที่พอดี: ทดสอบเท่าไหร่จึงพอ?

คุณรู้ว่าทำงานกับโค้ดทดสอบไม่ดีเจ็บปวดแค่ไหน ทุกครั้ง fix bug สร้าง bug ใหม่ 5 ตัว และตอน things do work ไม่รู้ว่า design มาแบบนั้น หรือใช้บังเอิญ

อีกด้านหนึ่ง คุณเพิ่งเขียน 200 tests สำหรับ feature เล็กน้อย ต้อง redesign working code เพื่อ hit 100% test coverage ไม่ได้搖感าว best-tested code กลาย 덜 readable และแย่ที่สุด burn out กับ app

ต้องมี middle ground ทดสอบเท่าไหร่纔พอ?

ดีถ้ามีเลขกลมเป็นกฎ: test code 2x app code หรือ 95% coverage แตแค่พูด "95% test coverage" ก็ ambiguous

Coverage เป็น indicator ของ well-tested code ไม่ใช่ guarantee เคยมี 100%-covered apps ที่มี bugs มากกว่า 85% coverage

ดังนั้น จำนวน testing ที่ถูกต้อง ไม่ใช่เรื่องตัวเลข แตเรื่องที่曖昧และยากนิยาม เกี่ยวกับการทดสอบ อย่างมีประสิทธิภาพ

Efficient Testing

Testing efficiently = ได้ประโยชน์มากที่สุด ด้วยความพยายามน้อยที่สุด ดีนะ?

แตมีอะไรเยอะไปใน efficient testing ช่วยคิด 3 อย่าง: size, isolation, focus

Size

Integration tests ดี พวกมัน mirror path ที่คนจริงเดินผ่าน app ทดสอบโค้ดทั้งหมดทำงานร่วมกันเหมือนโลกจริง

แต integration tests ช้า ยาว messy ถ้าอยากทดสอบส่วนเล็กอย่างละเอียด เพิ่ม overhead เยอะ

Unit tests เล็กกว่า รันเร็ว คิดง่าย เพราะเก็บแค่ส่วนเล็กน้อยในหัวตอนเขียน

แตอาจ fake เพราะทำงานใน unit test ไม่ได้หมายความว่าทำงานในโลกจริง (โดยเฉพาะถ้า mock เยอะ)

Balance ยังไง?

Unit tests เร็ว เขียนง่าย ไม่ค่าใช้จ่ายมากที่จะมีเยอะ ดีสำหรับ edge cases และ logic ซับซ้อน

พอมี well-tested pieces เยอะ ยังต้อง fill gaps ทดสอบ interaction และ full journeys แตเพราะ edge cases และ logic ทดสอบโดย unit tests แล้ว จึงต้องการ integration tests ที่ซับซ้อนช้า เพียง 몇 ตัว

เรียกว่า "Test Pyramid" integration tests น้อย ทับบน base ของ unit tests เยอะ อ่าน chapter 3 ของ Practicing Rails เพื่อรายละเอียด

Isolation

ยังไง ถ้าระบบซับซ้อน อาจต้อง tests infinite เพื่อ cover ทุก situation นี่อาจบอกว่า redesign app design หมายถึง parts ของระบบ depend กันเกินไป

เช่น object ที่มี states หลายแบบ:

case user.type when :admin message = admin_message when :user message = user_message when :author message = author_message else message = anonymous_message end if user.preferred_notification_method = :email send_email(message) elsif user.preferred_notification_method = :text send_text_message(message) else queue_notification(message) end

ทดสอบทุก path = 12 situations

  1. Admin, email
  2. Admin, text
  3. Admin, neither
  4. User, email
  5. User, text
  6. User, neither
  7. Author, email
  8. Author, text
  9. Author, neither
  10. Anonymous, email
  11. Anonymous, text
  12. Anonymous, neither

เยอะเพราะ "ส่งข้อความตาม notification method" และ "สร้างข้อความตาม user type" ผูกกัน อาจ擠 fewer tests แตไม่ชัด และขอ bugs

แตถ้าแยก?

message = get_message_based_on_user_type(user.type) send_notification(message, user.preferred_notification_method)

ตอนนี้ทดสอบแต่ละส่วนแยกได้

ส่วนแรก: ทดสอบ message ถูกต้องสำหรับแต่ละ user type

ส่วนสอง: ทดสอบ message ส่งถูกต้องตาม preferred_notification_method

ส่วนสาม: ทดสอบ parent method ส่ง message จาก get_message... ไป send_email_or_text

ตอนนี้ 8 states:

  1. User is admin
  2. User is user
  3. User is author
  4. User is anonymous
  5. preferred_notification_method = email
  6. preferred_notification_method = text
  7. preferred_notification_method = neither
  8. test parent method

ประหยัด 4 tests โดยแยก code ทดสอบแยก ตัวอย่างที่สองชัดเจนกว่าจะได้ด้วย fewer tests และเพิ่ม states แยก code กลายดีขึ้น

ใช้เวลาและฝึกหา balance ระหว่าง isolation และ readability แตถ้าแยก dependencies ที่ถูกต้อง ทดสอบน้อยลงได้มาก

Focus

App ควร well-tested แตไม่ได้หมายความว่าทุกส่วนพึงได้ attention เท่ากันบน tests

แม้ aim 100% coverage ยังทดสอบไม่หมดทุกอย่าง ไม่ทดสอบทุกบรรทัด text ใน views หรือ poll 5 วินาทีแทน 10

Focus = เขียน fewer, more useful tests และ quyết định consciously ใช้เวลาที่ไหนคุ้ม

Focus ยากเหมือนกัน คำถามที่ช่วย concentrate:

  • Interconnected กับ app มากแค่ไหน? พังแล้ว pieces อื่นๆ ตายกี่ตัว?
  • เปลี่ยนตามธรรมชาติ likely แค่ไหน? Tests fail เพราะ bug หรือเพราะ update UI text?
  • Impact ของการพังคืออะไร? Charge credit card สองครั้ง หรือแค่ missing text?
  • 用บ่อยแค่ไหน? Critical หรือ about page ซ่อนใน footer?

ไม่ควร 只 ทดสอบส่วนสำคัญ แตถ้าใช้ testing time 好 app จะ รู้สึก higher quality

พยายามทดสอบทุก path จะไม่ ship TDD ช่วย แตไม่แก้ปัญหาทั้งหมด

แตไม่ใช่ว่าไม่ควรทดสอบเลย

用 test pyramid เก็บ tests เล็ก แยก dependencies เปลี่ยน m*n test cases เป็น m+n และ prioritize ใช้เวลาทดสอบส่วนสำคัญ

คุณทดสอบเท่าไหร่? พิจารณา ideas นี้ไหม? รู้ยังไงว่าส่วนไหน focus? Comment บอกมาเลย!