ไปป์ไลน์สีเขียวที่ปล่อย API ที่เสียออกไปแย่ยิ่งกว่าไม่มีไปป์ไลน์เลยเสียอีก มันบอกทีมของคุณว่าทุกอย่างเรียบร้อยดีจนกระทั่งลูกค้าแจ้งปัญหา การตั้งค่าการทดสอบ API ส่วนใหญ่ใน CI เริ่มต้นอย่างแข็งแกร่งแล้วก็ค่อยๆ เสื่อมสลายไป: มีการครอบคลุมเพียงไม่กี่เอนด์พอยต์ จากนั้นชุดทดสอบก็เริ่มไม่เสถียร มีคนเพิ่ม continue-on-error เพื่อหยุดความน่ารำคาญ และภายในหนึ่งไตรมาส การทดสอบก็ยังคงทำงานอยู่แต่ไม่มีใครเชื่อถือได้ ไปป์ไลน์เป็นสีเขียวเพราะมันเรียนรู้ที่จะเพิกเฉยต่อความล้มเหลว
ทางแก้ไม่ใช่การเพิ่มการทดสอบให้มากขึ้น แต่เป็นการตัดสินใจบางประการเกี่ยวกับวิธีที่คุณออกแบบ รัน และควบคุมการทดสอบเหล่านั้นที่สามารถรับมือกับแรงกดดันในโลกแห่งความเป็นจริงได้ เช่น การแก้ไขด่วนในบ่ายวันศุกร์ หรือการเปลี่ยนแปลงโครงสร้างข้อมูลในสามบริการที่ลึกลงไป คู่มือนี้จะนำเสนอการตัดสินใจสิบสองประการเหล่านั้น พร้อมด้วยการตั้งค่าที่ชัดเจนที่คุณสามารถคัดลอกไปใช้ใน GitHub Actions, GitLab CI หรือรันเนอร์ใดๆ ที่คุณใช้งานอยู่แล้ว
แนวคิดหลักที่เชื่อมโยงทั้งหมดคือสิ่งเดียวกัน: การทดสอบ API ของคุณควรอยู่คู่กับสัญญา API ของคุณ รันได้ด้วยคำสั่งเดียวที่เคลื่อนย้ายได้ และล้มเหลวเสียงดังเมื่อสัญญานั้นถูกละเมิด นั่นคือเวิร์กโฟลว์ที่เราจะสร้างขึ้นด้วย Apidog ซึ่งเป็นแพลตฟอร์ม API ที่คุณสามารถออกแบบข้อกำหนด เขียนการยืนยันด้วยภาพ และรันชุดทดสอบทั้งหมดแบบ Headless ใน CI ผ่าน Apidog CLI คุณออกแบบการทดสอบเพียงครั้งเดียวในแอป จากนั้นรันชุดทดสอบนั้นในไปป์ไลน์ใดก็ได้ด้วยคำสั่งเดียว หากคุณต้องการทำตาม ให้ดาวน์โหลด Apidog และเตรียม API ของคุณให้พร้อม
หาก CI/CD เป็นสิ่งใหม่สำหรับคุณ สรุปสั้นๆ คือ: continuous integration รันการทดสอบของคุณทุกครั้งที่มีการคอมมิต และ continuous delivery จะโปรโมตบิลด์ที่ผ่านการทดสอบเหล่านั้น เรามีรายละเอียดเพิ่มเติมใน What Is CI/CD and How Does It Work ส่วนที่เหลือของบทความนี้สมมติว่าคุณมีไปป์ไลน์อยู่แล้ว และต้องการให้ส่วนของการทดสอบ API มีคุณค่าในนั้นจริงๆ
1. ใส่การทดสอบ API ในไปป์ไลน์ ไม่ใช่ในแท็บที่คุณลืมเปิด
แนวทางปฏิบัติที่ดีที่สุดข้อแรกคือสิ่งที่ผู้คนมักมองข้าม: รันการทดสอบ API ของคุณโดยอัตโนมัติ ทุกครั้งที่มีการพุช โดยไม่ต้องมีมนุษย์ตัดสินใจ ชุดทดสอบที่คุณรันด้วยตนเองก่อนการเปิดตัวคือรายการตรวจสอบ ไม่ใช่ตาข่ายนิรภัย เมื่อคุณจำได้ว่าจะรันมัน การเปลี่ยนแปลงที่ทำให้เกิดปัญหาอาจย้อนกลับไปถึงหกคอมมิตแล้ว
เชื่อมโยงชุดทดสอบเข้ากับขั้นตอนที่สำคัญ สำหรับทีมส่วนใหญ่ นั่นคือบน Pull Request ดังนั้น API ที่เสียจะบล็อกการรวมโค้ดแทนที่จะไปถึง main นี่คือรูปแบบขั้นต่ำใน GitHub Actions:
name: API Tests
on:
pull_request:
branches: [main]
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Apidog CLI
run: npm install -g apidog-cli
- name: Run API test suite
run: |
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" \
-e "$APIDOG_ENV_ID" \
-r cli,junit \
--out-dir ./test-results
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
SCENARIO_ID: ${{ vars.SCENARIO_ID }}
APIDOG_ENV_ID: ${{ vars.APIDOG_ENV_ID }}
นั่นคือการผสานรวมทั้งหมด CLI จะออกจากโปรแกรมด้วยรหัส 0 เมื่อการยืนยันทั้งหมดผ่าน และรหัสที่ไม่ใช่ศูนย์เมื่อมีรายการใดล้มเหลว ดังนั้น GitHub จะเปลี่ยนสถานะงานเป็นสีแดงเมื่อเกิดความล้มเหลวที่แท้จริงโดยไม่ต้องมีการเชื่อมต่อเพิ่มเติม เราครอบคลุมการตั้งค่า GitHub ทั้งหมดใน How to Automate API Tests in GitHub Actions; รูปแบบนี้สามารถนำไปใช้กับรันเนอร์ใดก็ได้
ประเด็นของแนวทางปฏิบัติที่ดีที่สุดข้อแรกคือการตัดสินใจทดสอบนั้นทำโดยเครื่องจักร ไม่ใช่นักพัฒนา มนุษย์ลืมได้ แต่ไปป์ไลน์ไม่ลืม
2. ทำให้คำสั่งรันสามารถเคลื่อนย้ายได้ระหว่างผู้ให้บริการ CI
ไปป์ไลน์มีการย้าย ทีมงานย้ายจาก Jenkins ไปยัง GitHub Actions, เพิ่ม GitLab สำหรับรีโพใหม่ หรือตั้งค่ารันเนอร์ที่โฮสต์เองเพื่อวัตถุประสงค์ในการปฏิบัติตามข้อกำหนด หากการทดสอบ API ของคุณผูกติดอยู่กับระบบนิเวศของปลั๊กอินของผู้ให้บริการรายใดรายหนึ่ง การย้ายแต่ละครั้งหมายถึงการเขียนใหม่ทั้งหมด
วิธีหลีกเลี่ยงคือการทำให้การเรียกใช้การทดสอบเป็นคำสั่งเชลล์เดียวที่รันเนอร์ใดๆ ก็สามารถเรียกใช้ได้ ด้วย Apidog CLI คำสั่งที่รันชุดทดสอบของคุณจะเหมือนกันไม่ว่าใครจะเรียกใช้ก็ตาม:
apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SCENARIO_ID" -e "$ENV_ID" -r cli,junit
บรรทัดเดียวกันนี้สามารถใช้ได้ในขั้นตอน run ของ GitHub Actions, บล็อก script ของ GitLab, ขั้นตอนเชลล์ของ Jenkins หรือส่วน script ของ Travis สิ่งที่เปลี่ยนไปคือแค่ส่วนที่ห่อหุ้มมันไว้เท่านั้น ตัวอย่างเช่น GitLab:
api-tests:
image: node:20
script:
- npm install -g apidog-cli
- apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SCENARIO_ID" -e "$ENV_ID" -r cli,junit
artifacts:
when: always
reports:
junit: ./test-results/*.xml
เนื่องจากการทำงานหนัก (การจัดเรียงคำขอ, การยืนยัน, การแก้ไขสภาพแวดล้อม) อยู่ใน CLI และคำจำกัดความของการทดสอบอยู่ใน Apidog ไฟล์ YAML ของไปป์ไลน์ของคุณจึงบางเบา เมื่อคุณเปลี่ยนผู้ให้บริการ คุณคัดลอกเพียงหกบรรทัด ไม่ใช่หกร้อยบรรทัด รูปแบบสำหรับ Jenkins มีอธิบายไว้ใน How to Integrate Apidog Automated Tests with Jenkins for CI/CD หากนั่นคือสแต็กของคุณ
3. ยืนยันพฤติกรรม ไม่ใช่แค่รหัสสถานะ
การทดสอบที่ตรวจสอบแค่ 200 OK จะยังคงผ่านไปได้ในขณะที่ API ของคุณส่งคืนอาร์เรย์ว่างเปล่า, สกุลเงินผิดพลาด หรือค่า null ในตำแหน่งที่ไคลเอนต์คาดหวังวัตถุ การทดสอบที่ตรวจสอบแค่รหัสสถานะเป็นสาเหตุที่ใหญ่ที่สุดที่ทำให้ไปป์ไลน์สีเขียวส่งการตอบกลับที่เสียหาย
การยืนยันที่แท้จริงจะตรวจสอบรูปทรงและเนื้อหาของการตอบกลับ: ฟิลด์ที่มีอยู่, ชนิดข้อมูลของฟิลด์เหล่านั้น, ค่าที่สำคัญต่อผู้ใช้งาน ใน Apidog คุณสร้างสิ่งเหล่านี้ด้วยภาพเทียบกับการตอบกลับ ดังนั้นคุณกำลังยืนยันจากเพย์โหลดจริง แทนที่จะเดา JSONPath ในหัวของคุณ การทดสอบการค้นหาคำสั่งซื้อที่แข็งแกร่งจะยืนยันว่าสถานะเป็น 200, order.total เป็นตัวเลข, currency เท่ากับค่าที่คุณส่ง และอาร์เรย์ items ไม่ว่างเปล่า การยืนยันแต่ละรายการนั้นแยกออกจากกันและล้มเหลวได้อย่างอิสระ ดังนั้นบิลด์สีแดงจะบอกคุณว่าสัญญาใดเสีย
- ยืนยันตามสัญญา ไม่ใช่ข้อมูล ตรวจสอบว่า
totalเป็นตัวเลข ไม่ใช่ว่าเท่ากับ49.99ค่าที่แน่นอนเปลี่ยนแปลงได้ แต่ชนิดข้อมูลไม่เปลี่ยน - หนึ่งข้อกังวลต่อหนึ่งการยืนยัน การรวมหกการตรวจสอบเข้าในการยืนยันเดียวจะซ่อนว่าอันไหนล้มเหลว
- ครอบคลุมเส้นทางที่ไม่พึงประสงค์ รหัส
400สำหรับอินพุตที่ไม่ดี และ401สำหรับโทเค็นที่ขาดหายไปก็เป็นส่วนหนึ่งของสัญญาของคุณเช่นกัน ทดสอบว่าพวกมันยังคงทำงานได้ถูกต้อง
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับการเขียนการยืนยันที่ทนทานต่อการปรับโครงสร้างโค้ด โปรดดูคู่มือของเราเกี่ยวกับ การยืนยัน API การยืนยันที่แข็งแกร่งคือสิ่งที่เปลี่ยน Smoke Test ให้เป็น Contract Test และ Contract Test คือสิ่งที่จับการถดถอยที่สำคัญได้
4. จัดการสภาพแวดล้อมและข้อมูลลับเป็นการตั้งค่า ไม่ใช่ค่าที่เขียนโค้ดไว้ตายตัว
การทดสอบของคุณทำงานกับเป้าหมายที่แตกต่างกัน: สแต็กภายในเครื่อง, API สำหรับ staging, เอนด์พอยต์สำหรับการทดสอบ Smoke Test ใน Production URL หลัก, โทเค็นการยืนยันตัวตน และ ID ของผู้เช่าล้วนเปลี่ยนแปลงไปในแต่ละสภาพแวดล้อม การเขียนค่าเหล่านี้ลงในโค้ดทดสอบโดยตรงเป็นวิธีที่ทำให้การทดสอบ staging ไปกระทบ production โดยไม่ตั้งใจ หรือทำให้โทเค็นไปปรากฏในประวัติ Git ของคุณ
เก็บสภาพแวดล้อมเป็นการตั้งค่าที่มีชื่อ และใส่ความแตกต่างเข้าไป ใน Apidog สภาพแวดล้อมจะเก็บ URL หลักและตัวแปรสำหรับเป้าหมายหนึ่ง คุณเลือกว่าการรัน CI จะใช้สภาพแวดล้อมใดด้วยแฟล็ก -e ไปป์ไลน์จะส่ง Access Token จากที่เก็บข้อมูลลับ ไม่ใช่จากไฟล์ในรีโพ:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" \
-e "$STAGING_ENV_ID" \
-r cli,junit
สถานการณ์เดียวกันนี้ เมื่อชี้ไปยังค่า -e ที่แตกต่างกัน จะกลายเป็นการทดสอบ Smoke Test สำหรับ Production ของคุณ ไม่มีอะไรเปลี่ยนแปลงเกี่ยวกับการทดสอบ มีเพียงสภาพแวดล้อมที่มันดำเนินการเท่านั้นที่เปลี่ยนไป เก็บ APIDOG_ACCESS_TOKEN ไว้ใน GitHub Secrets, ตัวแปร GitLab CI/CD หรือตัวจัดการข้อมูลรับรองของรันเนอร์ของคุณ และอ้างอิงด้วยชื่อ กฎง่ายๆ คือ: สิ่งใดก็ตามที่แตกต่างกันระหว่างสภาพแวดล้อม หรือสิ่งใดก็ตามที่เป็นความลับ ถือเป็นการตั้งค่า และการตั้งค่าจะถูกแทรกเข้ามาในขณะรันไทม์
5. ทำให้การทดสอบเป็นแบบกำหนดได้ เพื่อให้ไปป์ไลน์น่าเชื่อถือ
การทดสอบที่ไม่เสถียร (flaky test) คือการทดสอบที่ล้มเหลวด้วยเหตุผลที่ไม่เกี่ยวข้องกับโค้ดของคุณ มันยังเป็นวิธีที่เร็วที่สุดในการทำลายความน่าเชื่อถือของไปป์ไลน์ เมื่อชุดทดสอบ "บางครั้งก็ล้มเหลว" นักพัฒนาก็จะเริ่มรันงานซ้ำๆ จนกว่าจะขึ้นสีเขียว ซึ่งหมายความว่าความล้มเหลวที่แท้จริงจะถูกซ่อนอยู่ท่ามกลางความล้มเหลวปลอมๆ
ความไม่เสถียรในการทดสอบ API ส่วนใหญ่มาจากแหล่งที่มาที่คาดเดาได้ไม่กี่อย่าง:
- สถานะที่ใช้ร่วมกันและเปลี่ยนแปลงได้ (Shared mutable state) การทดสอบสองชุดสร้างผู้ใช้ด้วยอีเมลเดียวกัน หรือการทดสอบหนึ่งชุดขึ้นอยู่กับข้อมูลที่การทดสอบอื่นลบไป การทดสอบแต่ละชุดควรกำหนดและลบข้อมูลของตนเอง หรือใช้ผู้เช่าที่แยกจากกัน
- การสมมติฐานเรื่องเวลา การยืนยันผลลัพธ์แบบ Asynchronous ก่อนที่จะพร้อม หากการดำเนินการเป็นแบบ Eventually Consistent ให้วนตรวจสอบเงื่อนไขแทนการหยุดรอเป็นจำนวนวินาทีที่กำหนด
- การพึ่งพาจริงที่คุณควบคุมไม่ได้ แซนด์บ็อกซ์การชำระเงินของบุคคลที่สามที่จำกัดอัตราการใช้งานของคุณ หรือบริการต้นน้ำที่หยุดทำงานเพื่อการบำรุงรักษา ควรจำลองขอบเขตเหล่านั้นเพื่อให้การทดสอบของคุณวัด API ของคุณ ไม่ใช่เวลาทำงานของผู้อื่น Apidog สามารถสร้าง Mock สำหรับการพึ่งพาที่ไม่เสถียรจาก Schema ซึ่งจะช่วยป้องกันความไม่เสถียรจากภายนอกไม่ให้เข้ามาในบิลด์ของคุณ
- การขึ้นอยู่กับลำดับ การทดสอบที่ผ่านก็ต่อเมื่อรันตามลำดับที่เฉพาะเจาะจง ชุดทดสอบควรจะผ่านเมื่อรันในลำดับใดก็ได้ เพราะรันเนอร์ทำงานแบบขนานได้
การกำหนดได้คือความแตกต่างระหว่างไปป์ไลน์ที่ผู้คนให้ความเคารพกับไปป์ไลน์ที่พวกเขาเลี่ยงไปลงทุนกับการออกแบบตั้งแต่เนิ่นๆ การทดสอบที่ไม่เสถียรจะสะสมปัญหามากขึ้นเรื่อยๆ
6. ทำให้ขั้นตอนการทดสอบ API รวดเร็ว มิฉะนั้นนักพัฒนาจะเลี่ยงไปใช้งาน
ชุดทดสอบที่ใช้เวลา 20 นาทีในทุก Pull Request จะกลายเป็นภาระที่นักพัฒนาไม่พอใจและในที่สุดก็จะปิดใช้งานไป ความเร็วไม่ใช่สิ่งที่จะมีก็ดีใน CI แต่มันคือสิ่งที่ทำให้ชุดทดสอบยังคงทำงานต่อไปได้ เป้าหมายที่ทีมส่วนใหญ่ตั้งไว้คือขั้นตอน API ที่ใช้เวลาไม่เกินห้านาทีใน PRs
มีกลไกบางอย่างที่จะช่วยให้คุณทำได้:
- รันสถานการณ์อิสระแบบขนาน หากการทดสอบของคุณเป็นแบบกำหนดได้ (แนวทางปฏิบัติที่ดีที่สุดข้อห้า) ไม่มีอะไรจะหยุดคุณจากการแยกพวกมันออกไปทำงานแบบขนาน หรือให้รันเนอร์กระจายงาน ชุดทดสอบที่เป็นอิสระสามารถรันควบคู่กันไปได้
- จัดระดับการทดสอบของคุณ รันชุดทดสอบ Smoke Test ที่รวดเร็วในทุก PR และชุดทดสอบ Regression เต็มรูปแบบเมื่อรวมโค้ดเข้าสู่
mainหรือตามกำหนดการรายคืน ไม่ใช่ทุกการทดสอบจะต้องตรวจสอบทุกคอมมิต - แคชการติดตั้ง การแคชการติดตั้ง npm ทั่วโลกของ
apidog-cliในการรันแต่ละครั้งจะช่วยลดเวลาการตั้งค่าของแต่ละงาน - ล้มเหลวอย่างรวดเร็วในจุดที่ช่วยได้ และดำเนินการต่อในจุดที่ไม่ใช่ ใน PR ให้หยุดที่ความล้มเหลวแรกเพื่อให้ข้อเสนอแนะที่รวดเร็ว ในการรันเต็มรูปแบบรายคืน ให้ใช้
--on-error continueของ CLI เพื่อให้เอนด์พอยต์ที่เสียไปเพียงจุดเดียวไม่ไปบดบังอีกสี่สิบจุดที่เสียเช่นกัน
นี่คือรูปแบบการจัดลำดับชั้นใน GitHub Actions โดยมีการรัน Smoke Test อย่างรวดเร็วใน PRs และชุดทดสอบเต็มรูปแบบตามกำหนดเวลา:
on:
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * *' # nightly full regression
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install -g apidog-cli
- name: Run suite
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SMOKE_ID" -e "$ENV_ID" -r cli,junit --out-dir ./test-results
else
apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$FULL_ID" -e "$ENV_ID" -r cli,junit --on-error continue --out-dir ./test-results
fi
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
ขั้นตอนที่รวดเร็วที่ทำงานได้มีค่ามากกว่าขั้นตอนที่ละเอียดถี่ถ้วนแต่ถูกปิดใช้งาน
7. เผยแพร่ผลลัพธ์ที่เครื่องอ่านได้ ไม่ใช่แค่ข้อความจำนวนมากในคอนโซล
เมื่อบิลด์ล้มเหลว แค่บอกว่า "การทดสอบ API ล้มเหลว" นั้นไม่เพียงพอ คุณต้องรู้ว่าการยืนยันใดเสีย ในสถานการณ์ใด และในคำขอใด บิลด์สีแดงที่มีเอาต์พุตคอนโซลเป็นพันบรรทัดแทบไม่ดีไปกว่าการไม่มีการทดสอบเลย เพราะก็ยังต้องมีคนอ่านมันอยู่ดี
วิธีแก้ไขคือการส่งออกผลลัพธ์ในรูปแบบที่เซิร์ฟเวอร์ CI ของคุณสามารถแยกวิเคราะห์ได้โดยตรง JUnit XML เป็นรูปแบบผลการทดสอบ CI มาตรฐาน และเกือบทุกแพลตฟอร์มสามารถอ่านได้ Apidog CLI จะเขียนไฟล์นี้ด้วยรีพอร์ตเตอร์ junit:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" \
-e "$ENV_ID" \
-r cli,html,junit \
--out-dir ./test-results
คำสั่งนั้นจะสร้างผลลัพธ์สามมุมมองจากการรันเดียวกัน: cli สำหรับเอาต์พุตคอนโซลแบบเรียลไทม์, html สำหรับรายงานที่สามารถเรียกดูได้ที่มนุษย์สามารถเปิดดู และ junit สำหรับเครื่องมือ ชี้ไปป์ไลน์ของคุณไปยังไฟล์ XML และแพลตฟอร์มจะเปลี่ยนให้เป็นผลลัพธ์ที่มีโครงสร้างแยกตามแต่ละการทดสอบ:
- name: Publish test report
if: always()
uses: actions/upload-artifact@v4
with:
name: api-test-results
path: ./test-results
โปรดสังเกต if: always() คุณต้องการให้รายงานเผยแพร่แม้ในขณะที่การรันล้มเหลว เพราะเมื่อการรันล้มเหลวคือเวลาที่คุณต้องการมันมากที่สุด ผลลัพธ์ที่ได้นั้นคุ้มค่า: แทนที่จะเป็น "บิลด์ API เสียหาย" คุณจะได้รับข้อมูลว่า "การยืนยัน cart-total ในสถานการณ์การชำระเงินเริ่มล้มเหลว" ซึ่งจะเปลี่ยนการดีบักให้เป็นการเหลือบมองเพียงครั้งเดียว
8. ควบคุมการรวมโค้ดด้วย Branch Protection โดยอิงจากชุดทดสอบ
ชุดทดสอบที่ผ่านแต่ไม่บล็อกอะไรเลยก็เป็นเพียงแค่การแจ้งเตือนเท่านั้น จุดประสงค์ของ CI คือการทำให้โค้ดที่เสียหายไม่สามารถรวมเข้าได้ และนั่นต้องใช้ขั้นตอนเพิ่มเติมอีกหนึ่งขั้นที่ทีมส่วนใหญ่ไม่ได้ตั้งค่าไว้ นั่นคือ Branch Protection
รหัสออก (exit code) ทำงานในส่วนของเครื่องในพื้นที่ เนื่องจาก Apidog CLI จะออกด้วยรหัสที่ไม่ใช่ศูนย์เมื่อมีการยืนยันใดๆ ล้มเหลว งานจึงจะเปลี่ยนเป็นสีแดงเมื่อเกิดความล้มเหลวที่แท้จริง แต่สถานะสีแดงของงานใน PR เป็นเพียงคำแนะนำเท่านั้น จนกว่าคุณจะกำหนดให้การตรวจสอบนั้นจำเป็น ใน GitHub ให้ตั้งค่าการตรวจสอบ API-tests เป็น Required Status Check บน main; ปุ่มรวมโค้ดจะยังคงปิดใช้งานอยู่จนกว่าจะเปลี่ยนเป็นสีเขียว GitLab และ Bitbucket ก็มีการตั้งค่าที่เทียบเท่ากันในส่วน Merge-Request Settings
นี่คือความแตกต่างระหว่างชุดทดสอบที่สามารถจับการถดถอยได้กับชุดทดสอบที่บันทึกข้อมูลหลังเกิดเหตุการณ์ โดยไม่มีการตรวจสอบที่จำเป็น นักพัฒนาภายใต้แรงกดดันจากกำหนดเวลาอาจคลิกปุ่มรวมโค้ด และ API ที่เสียก็อาจถูกส่งออกไปพร้อมกับการตรวจสอบสีแดงที่อยู่ข้างๆ ด้วยการควบคุมนี้ แพลตฟอร์มจะปฏิเสธ การทดสอบจะหยุดเป็นเพียงข้อเสนอแนะและกลายเป็นกฎที่เครื่องมือบังคับใช้ให้คุณ
รวมสิ่งนี้เข้ากับผลลัพธ์ที่เครื่องอ่านได้จากแนวทางปฏิบัติที่ดีที่สุดข้อเจ็ดและการผสานรวมสถานะคอมมิต และโฮสต์ Git ของคุณจะแสดงการตรวจสอบที่ล้มเหลวอย่างแม่นยำใน PR วงจรข้อเสนอแนะจะปิดลง: พุช, ทดสอบ, ถูกบล็อก, แก้ไข, เขียว, รวม
9. สร้าง Test Coverage จาก API Spec ของคุณ แทนที่จะเขียนด้วยมือ
ส่วนที่ช้าที่สุดของการทดสอบ API คือการทำให้การทดสอบซิงค์กับ API เอนด์พอยต์ใหม่ทุกอันต้องมีการทดสอบใหม่ ฟิลด์ที่เปลี่ยนแปลงทุกอันต้องมีการอัปเดตการยืนยัน หากทำด้วยมือ การทดสอบมักจะล้าหลัง API เสมอ และช่องว่างนั้นคือที่ที่ Regression เกิดขึ้น
วิธีใช้ประโยชน์คือการขับเคลื่อนการทดสอบจากสัญญา หาก API ของคุณมี OpenAPI spec คุณสามารถสร้างโครงสร้างการทดสอบจากมันได้: หนึ่งคำขอต่อหนึ่งเอนด์พอยต์ โดยมี Schema ที่อธิบายรูปทรงของการตอบกลับที่คาดหวังอยู่แล้ว ใน Apidog Spec และการทดสอบจะอยู่ใน Workspace เดียวกัน ดังนั้นสถานการณ์ทดสอบจึงสามารถสร้างขึ้นได้โดยตรงจากเอนด์พอยต์ที่จัดทำเอกสารไว้ แทนที่จะคัดลอกมา เราจะอธิบายขั้นตอนการสร้างใน How to Generate API Test Collections from OpenAPI Specs
สิ่งนี้สำคัญใน CI เพราะการทดสอบที่ขับเคลื่อนด้วย Spec จะจับบั๊กที่เฉพาะเจาะจงและพบบ่อยได้ นั่นคือความแตกต่างระหว่างสิ่งที่เอกสารของคุณสัญญาไว้กับสิ่งที่ API ของคุณส่งคืน เมื่อการทดสอบถูกสร้างจาก Spec และรันเทียบกับ Live API ความไม่ตรงกันจะทำให้บิลด์ล้มเหลว สัญญาจะกลายเป็นสิ่งที่สามารถดำเนินการได้ คุณยังคงต้องเขียนการยืนยันที่เข้ารหัสความหมายทางธุรกิจด้วยมือ แต่คุณไม่จำเป็นต้องเขียนโค้ดซ้ำซ้อนว่า "เอนด์พอยต์นี้มีอยู่จริงและส่งคืนตามรูปแบบที่ระบุในเอกสารหรือไม่" ให้ Spec รับหน้าที่นั้นไป
10. ใช้การทดสอบแบบ Data-Driven เพื่อครอบคลุมกรณีขอบ (Edge Cases) โดยไม่ต้องสร้างสถานการณ์ซ้ำซ้อน
เอนด์พอยต์เดียวกันอาจมีพฤติกรรมแตกต่างกันไปตามข้อมูลอินพุต: คำสั่งซื้อที่ถูกต้อง, คำสั่งซื้อที่เกินวงเงินเครดิต, คำสั่งซื้อที่มี SKU ไม่รู้จัก, คำสั่งซื้อในสกุลเงินที่ไม่รองรับ การเขียนสถานการณ์แยกต่างหากสำหรับแต่ละกรณีเป็นวิธีที่ทำให้ชุดทดสอบพองตัวกลายเป็นหลายร้อยการทดสอบที่เกือบจะเหมือนกันซึ่งไม่มีใครดูแลรักษา
การทดสอบแบบ Data-Driven จะรันสถานการณ์เดียวเทียบกับข้อมูลอินพุตหลายแถว คุณกำหนดคำขอและการยืนยันเพียงครั้งเดียว จากนั้นป้อนตารางกรณีทดสอบ Apidog CLI รับไฟล์ข้อมูลด้วยแฟล็ก -d:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" \
-e "$ENV_ID" \
-d ./test-data/orders.csv \
-r cli,junit \
--out-dir ./test-results
แต่ละแถวใน orders.csv จะกลายเป็นการวนซ้ำหนึ่งครั้งพร้อมผลลัพธ์ที่ผ่านหรือล้มเหลวของตัวเอง หนึ่งสถานการณ์ การเรียกใช้ CLI หนึ่งครั้ง การครอบคลุมกรณีขอบอย่างเต็มที่ และรายงาน JUnit ที่แสดงว่าแถวอินพุตใดล้มเหลว สิ่งนี้ทำให้ชุดทดสอบของคุณมีขนาดเล็กแต่ครอบคลุมกว้าง ซึ่งเป็นสิ่งที่คุณต้องการในการทำงานแบบ CI คู่มือของเราเกี่ยวกับการ ทดสอบ API แบบ Data-Driven ด้วย CSV หรือ JSON จะอธิบายลึกซึ้งยิ่งขึ้นเกี่ยวกับการจัดโครงสร้างไฟล์ข้อมูล
รูปแบบนี้ให้ผลตอบแทนสูงสุดกับการตรวจสอบความถูกต้องและกฎราคา ซึ่งเป็นจุดที่เอนด์พอยต์เดียวมีสาขามากที่สุดและมีวิธีที่จะเกิดการถดถอยโดยไม่รู้ตัวได้มากที่สุด
11. รัน Post-Deploy Smoke Test กับสภาพแวดล้อมจริง
การทดสอบที่ผ่านกับ Staging จะบอกคุณว่าบิลด์นั้นดี แต่ไม่ได้บอกคุณว่าการ Deploy ทำงานได้ถูกต้อง การตั้งค่าที่คลาดเคลื่อน, ตัวแปรสภาพแวดล้อมที่หายไป, Load Balancer ที่เส้นทางผิด, ใบรับรองที่หมดอายุ: ทั้งหมดนี้จะผ่านการทดสอบก่อนการรวมโค้ดทุกอย่าง และจะเสียเฉพาะในสภาพแวดล้อมที่คุณ Deploy ไปใช้งานจริงเท่านั้น
มาตรการป้องกันคือ Smoke Test ที่รันหลังจากการ Deploy โดยเทียบกับเป้าหมายที่ใช้งานจริง มันเป็นชุดทดสอบขนาดเล็กและรวดเร็ว ครอบคลุมเฉพาะเส้นทางที่สำคัญที่สุด, Flow การยืนยันตัวตนของคุณ, เอนด์พอยต์สำหรับการอ่านและเขียนที่สำคัญที่สุดของคุณ โดยชี้ไปยัง Production หรือสภาพแวดล้อมที่เพิ่งถูก Deploy ไปใหม่ เนื่องจากคำสั่งรันสามารถเคลื่อนย้ายได้ (แนวทางปฏิบัติที่ดีที่สุดข้อสอง) และสภาพแวดล้อมเป็นเพียงการตั้งค่า (แนวทางปฏิบัติที่ดีที่สุดข้อสี่) นี่คือชุดทดสอบเดียวกันที่มีแฟล็ก -e ที่แตกต่างกัน:
smoke-after-deploy:
needs: deploy
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install -g apidog-cli
- name: Smoke test production
run: |
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SMOKE_SCENARIO_ID" \
-e "$PROD_ENV_ID" \
-r cli,junit \
--out-dir ./smoke-results
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
หาก Smoke Test ล้มเหลว นั่นคือสัญญาณให้คุณ Rollback ก่อนที่ผู้ใช้จะสังเกตเห็น สำหรับทีมที่ใช้ Blue-Green หรือ Canary Deploy คุณจะรันชุดทดสอบ Smoke Test กับเวอร์ชันใหม่ก่อนที่จะเปลี่ยนเส้นทางการจราจรไปยังมัน เพื่อให้ผู้ใช้จริงคนแรกของคุณไม่เคยเป็นผู้ที่พบข้อผิดพลาดในการ Deploy ต้นทุนคือเวลาไปป์ไลน์เพียงหนึ่งนาที ทางเลือกอื่นคือการทราบจากตั๋วสนับสนุน
12. ปฏิบัติต่อชุดทดสอบเหมือนโค้ดที่คุณต้องดูแลรักษา ไม่ใช่การตั้งค่าที่คุณทำเสร็จแล้ว
แนวทางปฏิบัติที่ดีที่สุดข้อสุดท้ายคือแนวคิด ชุดทดสอบ CI ไม่ใช่โปรเจกต์ที่คุณทำเสร็จสมบูรณ์ มันคือสินทรัพย์ที่คุณต้องดูแลรักษาควบคู่ไปกับ API ที่มันปกป้อง ทีมที่มีไปป์ไลน์ที่น่าเชื่อถือคือทีมที่ปฏิบัติต่อการทดสอบที่ไม่เสถียรว่าเป็นบั๊ก, ขั้นตอนที่ช้าว่าเป็น Technical Debt, และช่องว่างในการครอบคลุมว่าเป็น Regression ที่รอวันเกิดขึ้น
นิสัยบางอย่างที่ช่วยให้ชุดทดสอบมีสุขภาพดีในระยะยาว:
- เพิ่มการทดสอบพร้อมกับฟีเจอร์ เอนด์พอยต์ใหม่ควรมาพร้อมกับ Scenario ใน PR เดียวกัน ไม่ใช่ใน PR ที่ติดตามมาซึ่งไม่เคยได้รับการอนุมัติ
- แก้ไขการทดสอบที่ไม่เสถียรในวันที่มันปรากฏ การทดสอบที่ไม่เสถียรที่ถูกกักกันคือช่องว่างในการครอบคลุมที่มีไฟเขียวอยู่ อย่าปล่อยให้
continue-on-errorกลายเป็นค่าถาวร - ทบทวนสิ่งที่ชุดทดสอบไม่ได้ครอบคลุม ตรวจสอบเป็นระยะว่าเอนด์พอยต์ใดไม่มีการยืนยัน เอนด์พอยต์ที่ไม่ได้ทดสอบคือจุดที่ปัญหาการหยุดทำงานครั้งต่อไปจะเริ่มขึ้น
- เก็บการตั้งค่าไปป์ไลน์ไว้ในการควบคุมเวอร์ชัน ไฟล์ YAML ของคุณ, การกำหนดสภาพแวดล้อม และข้อมูลการทดสอบทั้งหมดควรอยู่ในรีโพ และได้รับการตรวจสอบเช่นเดียวกับการเปลี่ยนแปลงอื่นๆ
เนื่องจากคำจำกัดความของการทดสอบอยู่ใน Apidog และไปป์ไลน์มีเพียงการเรียกใช้งานเล็กน้อย การบำรุงรักษาส่วนใหญ่จึงเกิดขึ้นในจุดที่ง่าย: คุณเพิ่ม Scenario และการยืนยันในแอป และการตั้งค่า CI แทบจะไม่มีการเปลี่ยนแปลง ทีมที่ทำสิ่งนี้ได้ถูกต้องจะใช้เวลาไปกับการปรับปรุง Coverage ไม่ใช่การดูแลไฟล์ YAML สำหรับมุมมองที่กว้างขึ้นของการจัดระเบียบชุดทดสอบขนาดใหญ่ โปรดดู Apidog Test Suites: A Smarter Way to Automate API Testing
การรวบรวมทั้งหมด
แนวทางปฏิบัติทั้งสิบสองข้อนี้เสริมซึ่งกันและกัน คำสั่งรันที่เคลื่อนย้ายได้ทำให้ Post-Deploy Smoke Test กลายเป็นเรื่องเล็กน้อย การทดสอบแบบกำหนดได้ทำให้การทำงานแบบขนานปลอดภัย ซึ่งช่วยให้ขั้นตอนการทำงานรวดเร็ว และทำให้นักพัฒนายังคงใช้งานอยู่ ผลลัพธ์ที่เครื่องอ่านได้ทำให้ Branch Protection มีความหมาย เพราะตัวควบคุมจะชี้ไปยังการตรวจสอบที่ล้มเหลวที่เฉพาะเจาะจง แทนที่จะเป็นข้อความจำนวนมาก การทดสอบที่ขับเคลื่อนด้วย Spec และ Data-Driven ช่วยให้ชุดทดสอบครอบคลุมอย่างทั่วถึงโดยไม่ทำให้การบำรุงรักษาช้าลง
พื้นฐานทั่วไปคือการรักษาสภาพการทดสอบของคุณให้ใกล้เคียงกับสัญญา และสามารถรันได้จากคำสั่งเดียว นั่นคือเวิร์กโฟลว์ของ Apidog ในประโยคเดียว: ออกแบบ API และการทดสอบในที่เดียว จากนั้นรันชุดทดสอบนั้นในไปป์ไลน์ใดก็ได้ด้วย apidog run CLI จะออกด้วยรหัสที่ไม่ใช่ศูนย์เมื่อล้มเหลว ปล่อย JUnit ให้ CI ของคุณวิเคราะห์ และมีพฤติกรรมเหมือนกันไม่ว่า GitHub Actions, GitLab, Jenkins หรือรันเนอร์ที่โฮสต์เองจะเรียกใช้
เริ่มต้นจากสิ่งเล็กๆ เชื่อมโยงหนึ่ง Scenario ที่สำคัญเข้ากับไปป์ไลน์ PR ของคุณด้วยการยืนยันจริงและการตรวจสอบสถานะที่จำเป็น ทำให้วงจรนั้นน่าเชื่อถือ จากนั้นจึงเพิ่มส่วนที่เหลือ: การรันแบบจัดระดับ, กรณีขอบแบบ Data-Driven, Post-Deploy Smoke Test ไปป์ไลน์ที่คุณเชื่อถือคือไปป์ไลน์ที่ขึ้นสีแดงเฉพาะเมื่อมีบางสิ่งเสียหายอย่างแท้จริง และขึ้นสีเขียวเฉพาะเมื่อปลอดภัยที่จะ Deploy อย่างแท้จริง ดาวน์โหลด Apidog และสร้าง Scenario แรกได้เลยวันนี้
คำถามที่พบบ่อย
ความแตกต่างระหว่างการทดสอบ API ใน CI และ CI/CD คืออะไร? CI (continuous integration) จะรันการทดสอบ API ของคุณโดยอัตโนมัติทุกครั้งที่มีการคอมมิตหรือ Pull Request เพื่อจับการถดถอยได้ตั้งแต่เนิ่นๆ CD (continuous delivery) จะโปรโมตบิลด์ไปยังเป้าหมายการ Deploy เมื่อผ่านการตรวจสอบเหล่านั้น การทดสอบ API อยู่ในทั้งสองส่วน: ชุดทดสอบก่อนการรวมโค้ดจะควบคุมการรวมระบบ และชุดทดสอบ Smoke Test หลังการ Deploy จะตรวจสอบการส่งมอบ คำสั่ง Apidog CLI เดียวกันนี้ใช้ได้กับทั้งสองขั้นตอน
ฉันจำเป็นต้องเขียนโค้ดเพื่อรันการทดสอบ API ในไปป์ไลน์หรือไม่? ไม่จำเป็น คุณสร้างคำขอและการยืนยันด้วยภาพใน Apidog จากนั้นรันแบบ Headless ด้วยคำสั่ง apidog run เพียงคำสั่งเดียว ไปป์ไลน์ต้องการเพียงคำสั่งเดียวนี้ ซึ่งทำให้การตั้งค่า CI ของคุณบางเบา และหมายความว่าวิศวกร QA สามารถดูแลการทดสอบได้โดยไม่ต้องดูแลรักษากรอบงานที่อิงโค้ดทั้งหมด ขั้นตอนการทำงานแบบเต็มมีอยู่ใน How to Automate API Tests in CI/CD
ฉันจะหยุดไม่ให้การทดสอบ API ของฉันไม่เสถียรใน CI ได้อย่างไร? สาเหตุหลักสามประการคือข้อมูลทดสอบที่ใช้ร่วมกันและเปลี่ยนแปลงได้, การสมมติฐานเรื่องเวลาในการทำงานแบบ Asynchronous และการพึ่งพาบุคคลที่สามที่ควบคุมไม่ได้ ให้แต่ละการทดสอบมีข้อมูลของตัวเอง, วนตรวจสอบเงื่อนไขแบบ Asynchronous แทนการหยุดรอเป็นเวลาที่กำหนด และจำลองขอบเขตภายนอกที่คุณควบคุมไม่ได้ เป้าหมายคือชุดทดสอบที่ผ่านในลำดับใดก็ได้และในการรันใดๆ
ฉันจะทำให้การทดสอบ API ที่ล้มเหลวบล็อกการรวมโค้ดได้อย่างไร? มีสองส่วน ประการแรก, Test Runner จะต้องออกด้วยรหัสที่ไม่ใช่ศูนย์เมื่อเกิดความล้มเหลว; Apidog CLI ทำสิ่งนี้เมื่อมีการยืนยันใดๆ ล้มเหลว ดังนั้นงานจึงเปลี่ยนเป็นสีแดงโดยอัตโนมัติ ประการที่สอง, ทำเครื่องหมายงานนั้นเป็นการตรวจสอบสถานะที่จำเป็นในกฎ Branch Protection ของโฮสต์ Git ของคุณ ปุ่มรวมโค้ดจะยังคงปิดใช้งานอยู่จนกว่าการตรวจสอบจะผ่าน
ฉันสามารถรันการทดสอบ API ชุดเดียวกันใน GitHub Actions, GitLab และ Jenkins ได้หรือไม่? ได้ เนื่องจากตรรกะการทดสอบอยู่ใน Apidog และไปป์ไลน์เรียกใช้เพียง apidog run คำสั่งจึงเหมือนกันในทุกผู้ให้บริการ มีเพียงไฟล์ YAML หรือสคริปต์ไปป์ไลน์ที่ล้อมรอบเท่านั้นที่เปลี่ยนแปลง ความสามารถในการพกพานี้คือสิ่งที่ทำให้การย้ายผู้ให้บริการ CI เป็นการแก้ไขเพียงหกบรรทัดแทนที่จะเป็นการเขียนใหม่ทั้งหมด ดู How to Automate API Tests in GitHub Actions สำหรับการตั้งค่าเฉพาะของ GitHub
ขั้นตอนการทดสอบ API ของฉันควรเร็วแค่ไหน? ตั้งเป้าหมายให้ใช้เวลาไม่เกินห้านาทีใน Pull Request ทำได้โดยการรันชุดทดสอบ Smoke Test ที่รวดเร็วใน PRs และชุดทดสอบ Regression เต็มรูปแบบในตอนกลางคืน, การทำงานแบบขนานสำหรับ Scenario ที่เป็นอิสระ และการแคชการติดตั้ง CLI ขั้นตอนที่ช้าคือขั้นตอนที่นักพัฒนาจะปิดใช้งานในที่สุด ซึ่งจะทำให้จุดประสงค์ไม่สำเร็จ
