สรุปสาระสำคัญ (TL;DR)
ตัวแปรที่ตั้งค่าไว้ระหว่างการรันคำขอด้วยตนเองมักจะหายไปเมื่อคุณรันคอลเล็กชันเดียวกันใน Collection Runner ของ Postman สาเหตุหลักคือความไม่ตรงกันของขอบเขตตัวแปร: pm.environment.set มีพฤติกรรมแตกต่างกันใน runner เทียบกับโหมดแมนนวล และตัวแปรในคอลเล็กชันทำงานแตกต่างจากตัวแปรในสภาพแวดล้อม คู่มือนี้จะอธิบายว่าทำไมสิ่งนี้จึงเกิดขึ้นและวิธีแก้ไข จากนั้นจะแสดงให้เห็นว่า Apidog จัดการขอบเขตตัวแปรในลักษณะที่ลดความเสี่ยงในการตั้งค่าผิดพลาดได้อย่างไร
ปุ่ม
บทนำ
คุณได้ทดสอบ API ด้วยตนเองใน Postman คุณรันคำขอเข้าสู่ระบบ สคริปต์ก่อนคำขอ (pre-request script) ตั้งค่าโทเค็นการยืนยันตัวตน และคำขอที่ตามมาก็ใช้โทเค็นนั้นได้เป็นอย่างดี ทุกอย่างทำงานได้
จากนั้นคุณคลิก “Run Collection” (รันคอลเล็กชัน) runner เริ่มทำงาน คำขอเข้าสู่ระบบสำเร็จ แต่คำขอถัดไปล้มเหลวด้วยข้อผิดพลาด 401 โทเค็นหายไป
สถานการณ์นี้เกิดขึ้นซ้ำๆ ใน Stack Overflow และฟอรัมของ Postman ข้อความตอบกลับมักจะชี้ไปที่ขอบเขตตัวแปร (variable scope) แต่ไม่ค่อยมีการอธิบายภาพรวมทั้งหมดว่าทำไมพฤติกรรมจึงแตกต่างกันระหว่างการทดสอบด้วยตนเองและ runner
การทำความเข้าใจเรื่องนี้จำเป็นต้องเข้าใจลำดับชั้นของขอบเขตตัวแปรของ Postman เมื่อคุณเข้าใจอย่างชัดเจนแล้ว การแก้ไขก็จะเป็นเรื่องง่าย
ลำดับชั้นขอบเขตตัวแปรของ Postman
Postman มีขอบเขตตัวแปรห้าแบบ โดยเรียงลำดับจากความสำคัญสูงสุดไปต่ำสุด:
- Local variables (ตัวแปรท้องถิ่น) – ใช้ได้เฉพาะภายในสคริปต์ที่กำลังทำงานอยู่เท่านั้น ไม่สามารถเข้าถึงได้ข้ามคำขอ
- Data variables (ตัวแปรข้อมูล) – โหลดมาจากไฟล์ CSV หรือ JSON สำหรับการรันที่ขับเคลื่อนด้วยข้อมูล
- Collection variables (ตัวแปรคอลเล็กชัน) – กำหนดขอบเขตให้กับคอลเล็กชัน คงอยู่ตลอดคำขอในคอลเล็กชันนั้น
- Environment variables (ตัวแปรสภาพแวดล้อม) – กำหนดขอบเขตให้กับสภาพแวดล้อมที่เลือก คงอยู่ตลอดข้ามคอลเล็กชัน
- Global variables (ตัวแปรส่วนกลาง) – ใช้ได้ในคอลเล็กชันใดก็ได้ในสภาพแวดล้อมใดก็ได้
เมื่อ Postman แก้ไขการอ้างอิงตัวแปร เช่น {{token}} มันจะไล่ลงมาตามรายการนี้และใช้ค่าที่ตรงกันอันแรกที่พบ
ปัญหาคือคำว่า “คงอยู่” มีความหมายที่แตกต่างกันไป ขึ้นอยู่กับว่าคุณกำลังรันคอลเล็กชันอย่างไร
ทำไมตัวแปรจึงหายไปใน Collection Runner
ความแตกต่างระหว่างค่าปัจจุบัน (current value) และค่าเริ่มต้น (initial value)
ตัวแปรทุกตัวใน Postman มีสองฟิลด์: “ค่าเริ่มต้น (initial value)” และ “ค่าปัจจุบัน (current value)”
- ค่าเริ่มต้น (Initial value) จะซิงค์กับคลาวด์ของ Postman และแชร์กับเพื่อนร่วมทีม
- ค่าปัจจุบัน (Current value) เป็นค่าเฉพาะเครื่องของคุณและไม่ซิงค์
เมื่อคุณตั้งค่าตัวแปรด้วยโปรแกรมในสคริปต์โดยใช้ pm.environment.set('token', value), Postman จะอัปเดต ค่าปัจจุบัน (current value) ในสภาพแวดล้อมที่ใช้งานอยู่ของคุณ
ในโหมดการทดสอบด้วยตนเอง สิ่งนี้ทำงานได้ตามที่คาดไว้ เนื่องจากค่าปัจจุบันในเครื่องของคุณจะคงอยู่ตลอดการดำเนินการคำขอแต่ละรายการภายในเซสชันเดียวกัน
ใน Collection Runner พฤติกรรมจะเปลี่ยนไป runner จะเริ่มต้นแต่ละการรันจากสถานะปัจจุบันของสภาพแวดล้อมเมื่อเริ่มการรัน สคริปต์ที่อัปเดตตัวแปรในระหว่างการรันจะทำงานได้อย่างถูกต้องภายในรันนั้น แต่ถ้ารันเนอร์ถูกกำหนดค่าให้ล้างตัวแปรระหว่างการรัน หรือหากค่าเริ่มต้นว่างเปล่าและรันเนอร์ใช้สแนปช็อตสภาพแวดล้อมที่สดใหม่ คุณอาจจะพบว่าสคริปต์ของคุณทำงานแต่ตัวแปรไม่คงอยู่
ปัญหาตัวแปรสภาพแวดล้อม vs ตัวแปรคอลเล็กชัน
นี่คือกับดักที่พบบ่อยกว่า คุณกำลังตั้งค่าตัวแปรในสคริปต์หลังการตอบกลับ (post-response script):
pm.environment.set('token', pm.response.json().access_token);
สิ่งนี้จะตั้งค่าตัวแปรใน สภาพแวดล้อมที่ใช้งานอยู่ (active environment) แต่ Collection Runner มีตัวเลือกที่เรียกว่า “Keep variable values” (คงค่าตัวแปรไว้) หากไม่ได้เลือกช่องทำเครื่องหมายนี้ (ค่าเริ่มต้นคือไม่ได้เลือก) runner จะรีเซ็ตตัวแปรสภาพแวดล้อมกลับไปเป็นค่าเริ่มต้นหลังจากรันเสร็จสิ้น ค่าใดๆ ที่ตั้งค่าไว้ระหว่างการรันจะถูกทิ้งไป
หากคุณกำลังรันคอลเล็กชันโดยไม่ได้เลือกสภาพแวดล้อมไว้ pm.environment.set จะล้มเหลวอย่างเงียบๆ ไม่มีสภาพแวดล้อมให้เขียนถึง ตัวแปรจึงหายไป
ความไม่ตรงกันของขอบเขตระหว่างโหมดแมนนวลและโหมด runner
ในการทดสอบด้วยตนเอง โดยปกติคุณจะเลือกสภาพแวดล้อมไว้ และสภาพแวดล้อมนั้นจะคงอยู่ตลอดเซสชัน Postman ทั้งหมดของคุณ เมื่อคุณรันคำขอ ตั้งค่าตัวแปร และรันคำขออีกรายการ ทุกอย่างจะเกิดขึ้นในบริบทสภาพแวดล้อมที่คงอยู่เดียวกัน
Collection Runner จะสร้างบริบทการทำงานที่แยกต่างหาก มันจะโหลดสถานะของสภาพแวดล้อมเมื่อเริ่มต้นการทำงาน รันคำขอทั้งหมด และจากนั้น (เว้นแต่คุณจะเลือก “Keep variable values”) จะคืนค่าสภาพแวดล้อมกลับสู่สถานะก่อนการรัน
ซึ่งหมายความว่าตัวแปรที่ถูกตั้งค่าโดยคำขอหนึ่งใน runner จะพร้อมใช้งานสำหรับคำขอที่ตามมาในการรันเดียวกัน แต่จะไม่คงอยู่ในแผงสภาพแวดล้อมของคุณหลังจากรันเสร็จสิ้น เว้นแต่คุณจะเลือกให้คงอยู่ไว้อย่างชัดเจน
วิธีแก้ไข
วิธีแก้ไข 1: เลือก “Keep variable values” ใน runner
ใน Collection Runner ก่อนคลิก Run:
- มองหาตัวเลือก “Keep variable values” ในแผงการตั้งค่า runner
- เลือกช่องนี้
สิ่งนี้จะบอกให้ runner เขียนการเปลี่ยนแปลงตัวแปรใดๆ กลับไปยังสภาพแวดล้อมที่ใช้งานอยู่ของคุณหลังจากรันเสร็จสิ้น ตัวแปรที่ตั้งค่าโดยสคริปต์ในระหว่างการรันจะปรากฏในแผงสภาพแวดล้อมของคุณเมื่อรันเสร็จสมบูรณ์
ควรใช้เมื่อไหร่: เมื่อคุณต้องการให้ runner อัปเดตสถานะที่ใช้ร่วมกัน เช่น การรีเฟรชโทเค็นการยืนยันตัวตนที่เครื่องมืออื่นหรือการรันถัดไปจะใช้
ไม่ควรใช้เมื่อไหร่: เมื่อคุณกำลังรันหลายรอบ (iterations) และตัวแปรที่ตั้งค่าในรอบที่ 1 จะไปรบกวนรอบที่ 2 ในกรณีนั้น ให้ใช้ไฟล์ข้อมูลหรือรีเซ็ตตัวแปรอย่างชัดเจนเมื่อเริ่มต้นแต่ละรอบ
วิธีแก้ไข 2: ใช้ตัวแปรคอลเล็กชันแทนตัวแปรสภาพแวดล้อมสำหรับสถานะภายในรัน
หากตัวแปรจำเป็นต้องใช้ร่วมกันระหว่างคำขอภายใน Collection Run เดียวกันเท่านั้น ให้ใช้ตัวแปรคอลเล็กชันแทนตัวแปรสภาพแวดล้อม:
// In the post-response script of your login request:
pm.collectionVariables.set('token', pm.response.json().access_token);
// In the pre-request script of subsequent requests:
const token = pm.collectionVariables.get('token');
ตัวแปรคอลเล็กชันจะพร้อมใช้งานเสมอใน runner โดยไม่คำนึงว่าจะมีการเลือกสภาพแวดล้อมหรือไม่ ตัวแปรเหล่านี้จะคงอยู่ตลอดระยะเวลาของ Collection Run เป็นขอบเขตที่เหมาะสมสำหรับค่าที่ถูกตั้งค่าและใช้งานภายในคอลเล็กชันเดียว
วิธีแก้ไข 3: ตรวจสอบให้แน่ใจว่าได้เลือกสภาพแวดล้อมแล้วก่อนรัน
pm.environment.set จะล้มเหลวอย่างเงียบๆ เมื่อไม่มีสภาพแวดล้อมที่ใช้งานอยู่ ก่อนรันคอลเล็กชัน:
- เปิด Collection Runner
- ตรวจสอบว่ามีการเลือกสภาพแวดล้อมในเมนูแบบเลื่อนลง “Environment”
- หากคุณไม่ต้องการตัวแปรระดับสภาพแวดล้อม ให้ใช้ตัวแปรคอลเล็กชันแทน (วิธีแก้ไข 2)
วิธีแก้ไข 4: ใช้ค่าเริ่มต้นสำหรับตัวแปรที่ควรมีอยู่เสมอ
หากตัวแปรเช่น baseUrl จำเป็นต้องพร้อมใช้งานตั้งแต่คำขอแรกในการรัน ให้ตั้งค่าเป็นค่าเริ่มต้น (initial value) ในสภาพแวดล้อมของคุณ ไม่ใช่แค่ค่าปัจจุบัน (current value) เท่านั้น
ในตัวแก้ไขสภาพแวดล้อม:
- ตั้งค่าในฟิลด์ “Initial value” ไม่ใช่แค่ฟิลด์ “Current value”
- ค่าเริ่มต้นคือสิ่งที่ runner ใช้เป็นสถานะเริ่มต้น
หากตั้งค่าเฉพาะค่าปัจจุบันเท่านั้นและ runner ไม่สามารถเข้าถึงค่าปัจจุบันในเครื่องของคุณได้ (เช่น เพื่อนร่วมทีมรันคอลเล็กชัน หรือการรัน Newman/Apidog CLI) ตัวแปรนั้นจะเริ่มต้นด้วยค่าว่าง
วิธีแก้ไข 5: ดีบักด้วยการบันทึกคอนโซล (console logging)
เพิ่ม console.log ลงในสคริปต์ pre-request และ post-response ของคุณเพื่อดูว่าเกิดอะไรขึ้น:
// Pre-request script
console.log('token before request:', pm.collectionVariables.get('token'));
console.log('environment token:', pm.environment.get('token'));
เปิด Postman Console (View > Show Postman Console) ก่อนรันคอลเล็กชัน บันทึกจะแสดงให้คุณเห็นอย่างชัดเจนว่าตัวแปรแต่ละตัวถูกอ่านจากขอบเขตใด และมีค่าอะไรอยู่ในแต่ละขั้นตอน
วิธีที่ Apidog จัดการขอบเขตตัวแปร
Apidog ใช้ลำดับชั้นขอบเขตเดียวกัน: global, environment, collection และ local ความแตกต่างที่สำคัญอยู่ที่ UI
ในตัวแก้ไขตัวแปรของ Apidog ค่าเริ่มต้นและค่าปัจจุบันจะแสดงพร้อมป้ายกำกับและสีที่ชัดเจน อินเทอร์เฟซนี้ทำให้การตั้งค่าเฉพาะค่าปัจจุบันโดยไม่ได้ตั้งใจทำได้ยากขึ้น เมื่อสคริปต์ตั้งค่าตัวแปรโดยใช้ pm.environment.set (ซึ่ง Apidog รองรับเพื่อความเข้ากันได้กับ Postman) แผงสภาพแวดล้อมจะอัปเดตแบบเรียลไทม์เพื่อให้คุณเห็นการเปลี่ยนแปลงที่เกิดขึ้น
ตัวทดสอบ (test runner) ของ Apidog ก็ไม่รีเซ็ตค่าตัวแปรระหว่างขั้นตอนต่างๆ เว้นแต่คุณจะกำหนดค่าให้ทำเช่นนั้นอย่างชัดเจน พฤติกรรมเริ่มต้นคือการรักษาสถานะตัวแปรไว้ตลอดคำขอในการรัน ซึ่งตรงกับสิ่งที่นักพัฒนาส่วนใหญ่คาดหวังจากการทดสอบด้วยตนเอง
สำหรับสถานการณ์การทำงานเป็นทีม โมเดล local-first ของ Apidog หมายความว่าตัวแปรสภาพแวดล้อมจะถูกจัดเก็บไว้ในดิสก์ ไม่มีการซิงค์บนคลาวด์ที่เขียนทับค่าปัจจุบันของคุณระหว่างการรัน
สรุปข้อผิดพลาดที่พบบ่อย
| ข้อผิดพลาด | อาการ | วิธีแก้ไข |
|---|---|---|
| ไม่ได้เลือกสภาพแวดล้อม | pm.environment.set ล้มเหลวอย่างเงียบๆ |
เลือกสภาพแวดล้อมหรือใช้ตัวแปรคอลเล็กชัน |
| ตั้งค่าเฉพาะค่าปัจจุบัน | ตัวแปรหายไปใน CI หรือเครื่องของเพื่อนร่วมทีม | ตั้งค่าเริ่มต้นในตัวแก้ไขสภาพแวดล้อม |
| ไม่ได้เลือก “Keep variable values” | ตัวแปรถูกรีเซ็ตหลังจาก runner ทำงานเสร็จ | เลือก “Keep variable values” ในการตั้งค่า runner |
| ใช้ตัวแปรสภาพแวดล้อมสำหรับสถานะภายในรัน | ทำงานได้ในโหมดแมนนวล แต่ล้มเหลวใน runner | เปลี่ยนไปใช้ pm.collectionVariables.set |
| ตรวจสอบขอบเขตผิดพลาดในบันทึก | ตัวแปรมีอยู่แต่ใช้ค่าผิด | บันทึกทั้งสองขอบเขตและตรวจสอบลำดับความสำคัญในการแก้ไข |
คำถามที่พบบ่อย (FAQ)
ทำไม pm.environment.set จึงทำงานในโหมดแมนนวลแต่ไม่ทำงานใน runner? ในโหมดแมนนวล คุณมีเซสชันสภาพแวดล้อมที่คงอยู่ ใน runner สภาพแวดล้อมจะถูกโหลดเมื่อเริ่มการรันและโดยค่าเริ่มต้นจะถูกรีเซ็ตเมื่อสิ้นสุด สคริปต์ที่ตั้งค่าตัวแปรในระหว่างการรันยังคงทำงานสำหรับคำขอที่ตามมาในการรันนั้น แต่การเปลี่ยนแปลงจะไม่คงอยู่ในสภาพแวดล้อมของคุณเว้นแต่จะเลือก “Keep variable values”
ความแตกต่างระหว่าง pm.environment.set และ pm.collectionVariables.set คืออะไร? pm.environment.set จะเขียนไปยังสภาพแวดล้อมที่ใช้งานอยู่ ซึ่งใช้ร่วมกันได้ในทุกคอลเล็กชันที่ใช้สภาพแวดล้อมนั้น pm.collectionVariables.set จะเขียนไปยังขอบเขตที่ผูกกับคอลเล็กชันเฉพาะ สำหรับค่าที่สำคัญเฉพาะภายใน Collection Run เดียว ตัวแปรคอลเล็กชันจะเหมาะสมกว่าและไม่จำเป็นต้องเลือกสภาพแวดล้อม
ปัญหานี้เกิดขึ้นใน Newman ด้วยหรือไม่? ใช่ Newman มีโมเดลขอบเขตเดียวกัน โดยค่าเริ่มต้น Newman จะเริ่มต้นแต่ละการรันด้วยค่าเริ่มต้นของสภาพแวดล้อมที่ส่งออก และไม่เก็บการเปลี่ยนแปลงหลังจากรันเสร็จสิ้น เว้นแต่คุณจะใช้แฟล็ก --export-environment เพื่อเขียนสถานะสภาพแวดล้อมสุดท้ายลงในไฟล์
แฟล็ก --export-environment ใน Newman คืออะไร? มันบอกให้ Newman เขียนสถานะสุดท้ายของสภาพแวดล้อม รวมถึงค่าใดๆ ที่ตั้งค่าโดยสคริปต์ในระหว่างการรัน ลงในไฟล์ JSON หลังจากรันเสร็จสิ้น จากนั้นคุณสามารถส่งไฟล์นั้นเป็นสภาพแวดล้อมสำหรับการรันครั้งถัดไปได้ สิ่งนี้มีประโยชน์สำหรับไปป์ไลน์ที่การรันหนึ่งสร้างโทเค็นที่ใช้โดยการรันถัดไป
Apidog รองรับ pm.collectionVariables.set หรือไม่? ใช่ Apidog รองรับ Postman scripting API เต็มรูปแบบ รวมถึง pm.collectionVariables.set, pm.collectionVariables.get, pm.environment.set และ pm.environment.get คอลเล็กชันที่ย้ายมาจาก Postman ใช้ไวยากรณ์สคริปต์เดียวกัน
ฉันจะส่งตัวแปรจากคอลเล็กชันหนึ่งไปยังอีกคอลเล็กชันหนึ่งใน Postman ได้อย่างไร? ใช้ตัวแปรส่วนกลาง (global variables): pm.globals.set('token', value) ตัวแปรส่วนกลางจะคงอยู่ตลอดคอลเล็กชันและสภาพแวดล้อมตลอดอายุการใช้งานของเซสชัน Postman ระมัดระวังวิธีนี้ในการตั้งค่าทีม เนื่องจากตัวแปรส่วนกลางไม่มีขอบเขตและอาจทำให้เกิดการชนกันของชื่อ (name collisions) ได้
ปัญหาขอบเขตตัวแปรใน Postman เป็นหนึ่งในแหล่งที่มาที่น่าเชื่อถือที่สุดของผลลัพธ์เชิงลบที่ผิดพลาด (false negatives) ในชุดทดสอบ API การทดสอบที่ผ่านด้วยตนเองแต่ล้มเหลวใน runner ไม่ใช่การทดสอบที่คุณสามารถเชื่อถือได้ การทำความเข้าใจโมเดลขอบเขต การใช้ setter ที่เหมาะสมสำหรับบริบทที่ถูกต้อง และการเลือก “Keep variable values” เมื่อเหมาะสม เป็นสามขั้นตอนที่ช่วยแก้ไขปัญหาเหล่านี้ได้ส่วนใหญ่
ปุ่ม
