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

กำจัด Flaky Test Suites: คู่มือปฏิบัติสำหรับ Reliable API Testing

ผมทำงานกับ test suite ที่ frustrating มากเพราะ unreliable

Application ที่ test suite target คือ Rails API-only application Tests เขียนใน JavaScript ด้วย framework ชื่อ Chakram "API testing framework designed to perform end to end tests on JSON REST endpoints"

ปัญหาของ test suite คือไม่ deterministic function หรือ program เป็น deterministic ถ้า given same inputs ให้ same outputs เสมอ

Test suite นี้ pass run แรก pass run ที่สอง แต fail run ที่สาม โดยไม่มีการเปลี่ยนแปลง application code หรือ test code

ผมพบว่าสามารถทำให้ test suite กลับมา pass ด้วย rake db:reset Tests ที่ operate บน Rails development environment (ไม่ใช่ test environment) depend on database state ตอน test suite เริ่มรัน

บางครั้งเริ่ม fresh seeded database รัน test suite แล้วรันครั้งที่สองสำเร็จ อาจรันสามครั้งหรือมากกว่าได้ แต่บ่อยครั้ง test suite mess up data ต้อง rake db:reset อีกครั้งเพื่อคืน state ที่ test suite ใช้ได้

นี่ไมใช่วิธีที่ควรเป็น Test suite ควร fail เพียงเหตุเดียว: code ที่ test หยุดทำงาน properly

ควรทำอย่างไรแทน

ถ้า test suite setup แบบ problematic วิธีที่ถูกต้องคืออะไร?

Root cause คือ test suite depend on database reset ด้วย manual human แทน แต่ละ individual test ควร automatically put database ใน clean และ ready state ก่อนรัน (Typical วิธีคือ wipe database หลังรัน เพื่อไม่ "leak" data เข้า tests อื่น ไม่จำเป็นถ้าทุก test clear database ก่อนรัน แต่เป็น protective measure ดี)

Test suite ควร target Rails test environment ไม่ใช่ development environment Developer actions ใน development ไม่ควร interfere กับ test suite และ vice versa

ประเภท problematic dependencies อื่นๆ

ในเรื่องของผม problematic dependency คือ database ที่ไม่ clean properly

อีกประเภทคือ network request จินตนาการ test suite hit Twilio API รัน Tuesday pass รัน Wednesday fail ไม่รู้ว่า Twilio outage นั่นคือเหตุผล fail ไม่นาน outage resolved test suite pass อีกครั้ง

กลับสู่ idea ว่า test ควร fail เพียงเหตุเดียว: application code หยุดทำงาน

ถ้าต้องเขียน tests สำหรับ code ที่ interact กับ network วิธีดีกว่า (ถ้าใช้ Ruby/Rails) คือใช้ tool อย่าง VCR record network requests และ replay ต่อโดยไม่ใช้ internet

กรณีที่ outside dependencies OK

อาจ argue ว่าถ้า app depend on Twilio API และ Twilio down app จริงๆ break ดังนั้น test ควร fail ทำไง reconcile กับ idea ว่า tests ไม่ควร depend on outside conditions?

วิธี reconcile คือแยก integration tests (test multiple layers/systems together) และ unit tests (test single functionality in isolation)

ถ้าทีม decide consciously ว่าบาง tests จะ hit external services เพื่อ test multiple systems together ไม่มีอะไร "ผิด" (alternative คือ decide ไม่ test systems together เลย) ใน scenario นี้ ทีมแค่ต้อง aware ว่า network-dependent integration test suite ไม่ guaranteed deterministic และอาจ flake บางครั้ง Test suite แบบนี้ควรแยกจาก tests ที่ developers รันทุกวันเพื่อเช็ค regressions

แม้มี exception กฎ test ไม่ควร depend on outside conditions แต่ most of the time ควรปฏิบัติตาม ให้ test suite deterministic และ reliable