สิ่งที่ต้องพิจารณาเมื่อเขียนการทดสอบ E2E #frontend@twiiosendgrid
เผยแพร่แล้ว: 2020-09-19ที่ Twilio SendGrid เราเขียนการทดสอบแบบ end-to-end (E2E) จนถึงจุดสิ้นสุดของคุณลักษณะใหม่หรือวงจรการพัฒนาเพจ เพื่อให้แน่ใจว่าทุกส่วนเชื่อมต่อและทำงานอย่างถูกต้องระหว่างส่วนหน้าและส่วนหลังจากมุมมองของผู้ใช้ปลายทาง
เราได้ทดลองกับเฟรมเวิร์กและไลบรารีการทดสอบ E2E ต่างๆ เช่น เฟรมเวิร์ก Ruby Selenium ภายในของเราเอง, WebdriverIO และโดยพื้นฐานแล้ว Cypress มานานกว่าสองปีตามที่เน้นใน ส่วนที่หนึ่ง และ ส่วนที่สอง ของชุดโพสต์บล็อกที่บันทึกการย้ายข้อมูลทั้งหมดของเรา โซลูชั่น โดยไม่คำนึงถึงเฟรมเวิร์กหรือไลบรารีที่เราใช้ เราพบว่าตัวเองกำลังถามคำถามเดียวกันเกี่ยวกับคุณลักษณะที่เราสามารถทำให้เป็นอัตโนมัติและเขียนการทดสอบ E2E สำหรับได้ หลังจากระบุคุณลักษณะที่เราสามารถทดสอบได้ เรายังสังเกตเห็นว่าเราใช้กลยุทธ์ทั่วไปแบบเดียวกันซ้ำแล้วซ้ำเล่าในการเขียนและตั้งค่าการทดสอบ
โพสต์บล็อกนี้ไม่จำเป็นต้องมีความรู้เกี่ยวกับการเขียนการทดสอบ E2E ในไลบรารีหรือเฟรมเวิร์กใด ๆ มาก่อน แต่จะช่วยคุณได้หากคุณเคยเห็นเว็บแอปพลิเคชันและสงสัยเกี่ยวกับวิธีการทำงานอัตโนมัติในเบราว์เซอร์ให้ดีที่สุดเพื่อทดสอบหน้าเว็บให้ทำงานอย่างถูกต้อง เรามุ่งหวังที่จะแนะนำคุณเกี่ยวกับวิธีคิดเกี่ยวกับการทดสอบ E2E เพื่อให้คุณสามารถใช้คำถามเหล่านี้และกลยุทธ์ทั่วไปในการเขียนการทดสอบกับเฟรมเวิร์กใดก็ได้ที่คุณเลือก
คำถามที่ถามว่าคุณสามารถทำการทดสอบ E2E โดยอัตโนมัติได้หรือไม่
เมื่อพูดถึงการเขียนการทดสอบ E2E เราจำเป็นต้องตรวจสอบให้แน่ใจว่าโฟลว์ในหน้าที่เราทดสอบในแอปพลิเคชันของเราตรงตามเกณฑ์บางประการ มาดูคำถามระดับสูงบางคำถามที่เราถามตัวเองเพื่อพิจารณาว่าการทดสอบ E2E สามารถทำให้เป็นแบบอัตโนมัติได้หรือไม่
1. เป็นไปได้ไหมที่จะรีเซ็ตข้อมูลผู้ใช้กลับเป็นสถานะหนึ่งก่อนการทดสอบแต่ละครั้งด้วยวิธีที่เชื่อถือได้ เช่น API หากไม่มีวิธีรีเซ็ตผู้ใช้ให้กลับสู่สถานะที่คุณต้องการได้อย่างน่าเชื่อถือ ระบบจะไม่ทำงานอัตโนมัติและคาดว่าจะทำงานเป็นส่วนหนึ่งของการทดสอบการบล็อกก่อนนำไปใช้งาน นอกจากนี้ยังเป็น antipattern และมักจะไม่มีการกำหนดเพื่อให้ผู้ใช้กลับสู่สถานะที่แน่นอนผ่าน UI เนื่องจากมันช้าและขั้นตอนอัตโนมัติผ่าน UI นั้นไม่สม่ำเสมอเพียงพอแล้ว การเรียก API เพื่อรีเซ็ตสถานะของผู้ใช้มีความน่าเชื่อถือมากกว่าโดยไม่ต้องเปิดหน้าในเบราว์เซอร์ อีกทางเลือกหนึ่งหากคุณมีบริการที่มีอยู่คือการสร้างผู้ใช้ใหม่ก่อนการทดสอบแต่ละครั้งด้วยข้อมูลที่เหมาะสม ตราบใดที่เรารีเซ็ตผู้ใช้ที่คงอยู่หรือสร้างผู้ใช้ก่อนการทดสอบแต่ละครั้ง เราก็สามารถมุ่งเน้นไปที่ส่วนที่เรากำลังทดสอบบนหน้า
2. เรามีการควบคุมคุณสมบัติ, API หรือระบบที่เราตั้งใจจะทดสอบหรือไม่? หากเป็นบริการของบุคคลที่สามที่คุณใช้ในการเรียกเก็บเงินหรือคุณลักษณะอื่น ๆ มีวิธีใดบ้างที่จะล้อเลียนพวกเขาหรือให้ทำงานโดยกำหนดด้วยค่าบางอย่าง คุณต้องการควบคุมการทดสอบให้ได้มากที่สุดเพื่อลดความไม่แน่นอน คุณสามารถสร้างผู้ใช้ทดสอบโดยเฉพาะด้วยทรัพยากรหรือข้อมูลที่แยกได้ต่อการทดสอบการทำงาน เพื่อไม่ให้ได้รับผลกระทบจากสิ่งอื่นใด
3. บริการหรือคุณสมบัติมีความสอดคล้องเพียงพอที่จะทำงานภายในระยะหมดเวลาที่เหมาะสมหรือไม่? บ่อยครั้งคุณอาจต้องใช้การโพลหรือรอให้ข้อมูลบางอย่างได้รับการประมวลผลและไปยังฐานข้อมูล (เช่น การอัปเดตแบบอะซิงโครนัสที่ช้ากว่าและเหตุการณ์อีเมลที่ทริกเกอร์) หากบริการเหล่านั้นมักเกิดขึ้นภายในกรอบเวลาที่เหมาะสมและเชื่อถือได้ คุณสามารถตั้งค่าระยะหมดเวลาการโพลที่เหมาะสมได้ในขณะที่คุณรอให้องค์ประกอบ DOM เฉพาะแสดงขึ้นหรืออัปเดตข้อมูล
4. เราสามารถเลือกองค์ประกอบที่เราต้องการโต้ตอบกับหน้าได้หรือไม่? คุณกำลังจัดการกับ iframes หรือองค์ประกอบที่สร้างขึ้นโดยที่คุณไม่มีอำนาจควบคุมและไม่สามารถแก้ไขได้หรือไม่? ในการโต้ตอบกับองค์ประกอบบนหน้าเว็บ คุณสามารถเพิ่มตัวเลือกที่เฉพาะเจาะจงมากขึ้น เช่น แอตทริบิวต์ `data-hook` หรือ `data-testid` แทนที่จะเลือกบน id หรือชื่อคลาส รหัสและชื่อคลาสมีแนวโน้มที่จะเปลี่ยนแปลงมากกว่าเนื่องจากมักเกี่ยวข้องกับสไตล์ ลองนึกภาพการพยายามเลือกชื่อคลาสหรือรหัสที่แฮชจากองค์ประกอบที่มีสไตล์หรือโมดูล CSS สำหรับองค์ประกอบที่สร้างโดยบุคคลที่สามหรือไลบรารีองค์ประกอบโอเพนซอร์ส เช่น react-select คุณสามารถรวมองค์ประกอบเหล่านั้นด้วยองค์ประกอบหลักด้วยแอตทริบิวต์ `data-hook` และเลือกรายการย่อยด้านล่าง ในการจัดการกับ iframes เราได้สร้างคำสั่งที่กำหนดเองเพื่อแยกองค์ประกอบ DOM ที่เราจำเป็นต้องยืนยันและดำเนินการ ซึ่งเราจะยกตัวอย่างในภายหลัง
มีข้อควรพิจารณาเพิ่มเติมที่ต้องนำมาพิจารณา แต่ทั้งหมดนี้รวมเป็นคำถามเดียว: เราสามารถทำซ้ำการทดสอบ E2E นี้ในลักษณะที่สอดคล้องกันและทันเวลาและบรรลุผลลัพธ์เดียวกันได้หรือไม่
กลยุทธ์ทั่วไปในการเขียนแบบทดสอบ E2E
1. พิจารณากรณีทดสอบมูลค่าสูงที่เราสามารถทำให้เป็นอัตโนมัติ ได้ ตัวอย่างบางส่วน ได้แก่ การทดสอบ Happy Path ซึ่งครอบคลุมโฟลว์ฟีเจอร์ส่วนใหญ่: การดำเนินการ CRUD ผ่าน UI สำหรับข้อมูลโปรไฟล์ของผู้ใช้ การกรองตารางเพื่อผลลัพธ์ที่ตรงกันจากข้อมูลบางส่วน การสร้างโพสต์ หรือการตั้งค่าคีย์ API กรณีขอบและการจัดการข้อผิดพลาดอื่นๆ อาจดีกว่าที่จะครอบคลุมด้วยการทดสอบหน่วยและการรวม เรียกใช้คำถามที่เรากล่าวถึงในส่วนก่อนหน้าเพื่อช่วยย่อรายการกรณีทดสอบของคุณ
2. ลองนึกถึงวิธีทดสอบซ้ำโดยการตั้งค่าหรือแยกส่วน API ออกให้มากที่สุด สำหรับกรณีทดสอบอัตโนมัติที่มีมูลค่าสูงและมีมูลค่าสูง ให้เริ่มสังเกตว่าสิ่งใดที่คุณควรตั้งค่าผ่าน API ตัวอย่างบางส่วน ได้แก่ การ seed ผู้ใช้ด้วยข้อมูลที่เหมาะสม หากผู้ใช้ไม่มีข้อมูลที่กรองได้เพียงพอสำหรับการแบ่งหน้า หากข้อมูลของผู้ใช้หมดอายุในกรอบเวลาต่อเนื่อง 30 วัน หรือหากเราจำเป็นต้องฉีกข้อมูลบางส่วนที่เหลือจากความสำเร็จหรือไม่สมบูรณ์ การทดสอบก่อนที่การทดสอบปัจจุบันจะเริ่มอีกครั้ง การทดสอบควรจะสามารถรันและตั้งค่าตัวเองในสถานะทำซ้ำได้เหมือนกัน ไม่ว่าการทดสอบครั้งสุดท้ายจะสำเร็จหรือล้มเหลวอย่างไร
สิ่งสำคัญที่ต้องคิดคือ ฉันจะรีเซ็ตข้อมูลของผู้ใช้รายนี้กลับไปที่จุดเริ่มต้นได้อย่างไร เพื่อที่ฉันจะได้ทดสอบเฉพาะส่วนที่ต้องการของฟีเจอร์ที่ต้องการ
ตัวอย่างเช่น หากคุณต้องการทดสอบความสามารถของผู้ใช้ในการเพิ่มโพสต์เพื่อให้ปรากฏในรายชื่อโพสต์ของผู้ใช้ จะต้องลบโพสต์นั้นเสียก่อน
3. เดินในรองเท้าของลูกค้าของคุณและติดตามขั้นตอน UI ที่จำเป็นเพื่อให้ขั้นตอนคุณลักษณะสมบูรณ์ บันทึกขั้นตอนสำหรับลูกค้าเพื่อให้ขั้นตอนหรือการดำเนินการทั้งหมดเสร็จสมบูรณ์ ติดตามสิ่งที่ผู้ใช้ควรหรือไม่ควรเห็นหรือโต้ตอบหลังจากแต่ละขั้นตอน เราจะทำการตรวจสอบสติและการยืนยันไปพร้อมกันเพื่อให้แน่ใจว่าผู้ใช้กำลังเผชิญกับลำดับเหตุการณ์ที่เหมาะสมสำหรับการกระทำของพวกเขา จากนั้นเราจะแปลการตรวจสอบสติเป็นคำสั่งและการยืนยันแบบอัตโนมัติ
4. รักษาการเปลี่ยนแปลงและทำให้โฟลว์เป็นอัตโนมัติโดยเพิ่มตัวเลือกเฉพาะและนำออบเจ็กต์ของเพจไปใช้ (หรือแรปเปอร์ชนิดอื่น) ตรวจสอบขั้นตอนที่คุณจดไว้เพื่อดูวิธีควบคุมและทำตามขั้นตอนของฟีเจอร์ เพิ่มตัวเลือกที่เจาะจงมากขึ้น เช่น แอตทริบิวต์ `data-hook` ให้กับองค์ประกอบที่ผู้ใช้โต้ตอบด้วยปุ่มต่างๆ เช่น ปุ่ม โมดอล อินพุต แถวของตาราง การแจ้งเตือน และการ์ด หากต้องการ คุณสามารถสร้างออบเจ็กต์หน้า ไฟล์แรปเปอร์ หรือไฟล์ตัวช่วยโดยอ้างอิงองค์ประกอบเหล่านั้นผ่านตัวเลือกที่คุณเพิ่ม จากนั้น คุณสามารถใช้ฟังก์ชันที่ใช้ซ้ำได้เพื่อโต้ตอบกับองค์ประกอบที่ดำเนินการได้ของเพจ
5. แปลขั้นตอนของผู้ใช้ที่คุณบันทึกไว้ในการทดสอบ Cypress ด้วยตัวช่วยที่คุณสร้างขึ้น ในการทดสอบ เรามักจะเข้าสู่ระบบผู้ใช้ผ่าน API และเก็บรักษาคุกกี้ของเซสชันก่อนที่กรณีทดสอบแต่ละกรณีจะทำงานเพื่อคงสถานะการเข้าสู่ระบบ จากนั้นเราจะตั้งค่าหรือทำลายข้อมูลของผู้ใช้ผ่าน API เพื่อให้มีจุดเริ่มต้นที่สอดคล้องกัน เมื่อทุกอย่างพร้อมแล้ว เราจะไปที่หน้าที่เราจะทดสอบคุณสมบัติของเราโดยตรง เราดำเนินการตามขั้นตอนสำหรับโฟลว์ เช่น การสร้าง อัปเดต หรือลบโฟลว์ โดยยืนยันว่าสิ่งที่ควรเกิดขึ้นหรือปรากฏบนเพจระหว่างทาง เพื่อเร่งความเร็วในการทดสอบและลดความเหลื่อมล้ำ ให้หลีกเลี่ยงการรีเซ็ตหรือสร้างสถานะผ่าน UI และเลี่ยงผ่านสิ่งต่างๆ เช่น การเข้าสู่ระบบผ่านหน้าเข้าสู่ระบบ หรือการลบสิ่งต่างๆ ผ่าน UI เพื่อเน้นไปที่ส่วนต่างๆ ที่คุณต้องการทดสอบ ตรวจสอบให้แน่ใจว่าได้ทำส่วนเหล่านั้นในตะขอ "ก่อน" หรือ "ก่อนแต่ละอัน" เสมอ มิฉะนั้น หากคุณใช้ hooks "หลัง" หรือ "หลังแต่ละ" การทดสอบอาจล้มเหลวในระหว่างนั้น ทำให้ขั้นตอนการล้างข้อมูลของคุณไม่ถูกเรียกใช้ และทำให้การทดสอบครั้งต่อๆ ไปล้มเหลว
6. ตอกและประทับตราทดสอบความหลุดลุ่ย หลังจากใช้การทดสอบและการทดสอบผ่านสองสามครั้งในเครื่อง อาจเป็นการยั่วยวนให้ตั้งค่าคำขอดึง รวมทันที และให้การทดสอบทำงานตามกำหนดเวลากับชุดทดสอบที่เหลือของคุณ หรือทริกเกอร์ในขั้นตอนการปรับใช้ของคุณ ก่อนที่คุณจะทำเช่นนั้น:
- ขั้นแรก ลองปล่อยให้ผู้ใช้อยู่ในสถานะต่างๆ และดูว่าการทดสอบของคุณยังคงผ่านหรือไม่เพื่อให้แน่ใจว่าคุณมีขั้นตอนการตั้งค่าที่เหมาะสม
- ถัดไป ตรวจสอบการรันการทดสอบของคุณแบบคู่ขนานเมื่อถูกทริกเกอร์ระหว่างหนึ่งในโฟลว์การปรับใช้ของคุณ วิธีนี้ช่วยให้คุณเห็นว่าทรัพยากรถูกผู้ใช้คนเดียวกันเหยียบย่ำทรัพยากรหรือไม่ และมีเงื่อนไขการแข่งขันเกิดขึ้นหรือไม่
- จากนั้น สังเกตว่าการทดสอบของคุณทำงานอย่างไรในโหมดหัวขาดในคอนเทนเนอร์ Docker เพื่อดูว่าคุณอาจต้องเพิ่มระยะหมดเวลาหรือปรับตัวเลือกใดๆ หรือไม่
เป้าหมายคือการดูว่าการทดสอบของคุณทำงานอย่างไรในการทดสอบซ้ำๆ ที่ทำงานภายใต้เงื่อนไขที่แตกต่างกัน และทำให้การทดสอบนั้นเสถียรและสม่ำเสมอที่สุดเท่าที่จะเป็นไปได้ ดังนั้นเราจึงใช้เวลาน้อยลงในการกลับไปแก้ไขการทดสอบและมุ่งเน้นที่การตรวจจับจุดบกพร่องที่เกิดขึ้นจริงในสภาพแวดล้อมของเรามากขึ้น
นี่คือตัวอย่างโครงร่างการทดสอบ Cypress ที่เราได้สร้างคำสั่งสนับสนุนการเข้าสู่ระบบส่วนกลางที่เรียกว่า `cy.login(ชื่อผู้ใช้ รหัสผ่าน)` เราตั้งค่าคุกกี้อย่างชัดเจนและเก็บรักษาไว้ก่อนแต่ละกรณีทดสอบ เพื่อให้เราสามารถอยู่ในระบบและดำเนินการได้โดยตรง ไปยังหน้าที่เรากำลังทดสอบ นอกจากนี้เรายังดำเนินการตั้งค่าหรือทำลาย API และข้ามหน้าเข้าสู่ระบบทุกครั้งดังที่แสดงด้านล่าง
จบความคิด
นอกเหนือจากการเปรียบเทียบว่าโซลูชัน E2E ใดดีที่สุดในการใช้งานแล้ว สิ่งสำคัญคือต้องใช้ความคิดที่เหมาะสมสำหรับการทดสอบ E2E ด้วย จำเป็นอย่างยิ่งที่จะต้องถามคำถามก่อนว่าคุณสมบัติที่คุณต้องการทดสอบนั้นตรงกับข้อกำหนดของระบบอัตโนมัติหรือไม่ คุณควรมีวิธีรีเซ็ตผู้ใช้หรือข้อมูลกลับสู่สถานะที่แน่นอน (เช่น ผ่าน API) เพื่อให้คุณสามารถมุ่งเน้นไปที่สิ่งที่คุณกำลังพยายามตรวจสอบ
หากไม่มีวิธีที่เชื่อถือได้ในการรีเซ็ตผู้ใช้หรือข้อมูลของคุณไปยังจุดเริ่มต้นที่เหมาะสม คุณควรพิจารณาเครื่องมือสร้างและ API สำหรับการสร้างผู้ใช้ด้วยการกำหนดค่าบางอย่าง คุณอาจลองล้อเลียนสิ่งที่คุณควบคุมได้เพื่อให้การทดสอบมีความเสถียรและสม่ำเสมอที่สุด มิเช่นนั้น คุณควรพิจารณาถึงคุณค่าและข้อแลกเปลี่ยนกับทีมของคุณ คุณลักษณะนี้เป็นคุณลักษณะหนึ่งที่คุณควรปล่อยให้เป็นการทดสอบหน่วยหรือการทดสอบการถดถอยด้วยตนเองเมื่อมีการเปลี่ยนแปลงโค้ดใหม่หรือไม่
สำหรับคุณสมบัติเหล่านั้น คุณสามารถทำให้การทดสอบ E2E เป็นอัตโนมัติได้ มักจะมีประโยชน์มากที่สุดที่จะครอบคลุมเส้นทางความสุขหลักของผู้ใช้ของคุณ เป็นอีกครั้งที่ทำให้สิ่งต่างๆ ทำซ้ำได้ในเวลาที่เหมาะสมและสม่ำเสมอ และขจัดความไม่แน่นอนในขณะที่คุณเขียนการทดสอบ E2E ด้วยเฟรมเวิร์กหรือไลบรารีใดๆ ที่คุณต้องการ
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการทดสอบ Cypress E2E โดยเฉพาะ โปรดดูแหล่งข้อมูลต่อไปนี้:
- ภาพรวม 1,000 ฟุตของการเขียนแบบทดสอบ Cypress
- TypeScript ทุกสิ่งในการทดสอบ Cypress ของคุณ
- การจัดการกับกระแสอีเมลในการทดสอบ Cypress
- แนวคิดสำหรับการกำหนดค่า การจัดระเบียบ และการรวมการทดสอบ Cypress ของคุณ
- การรวมการทดสอบ Cypress กับ Docker, Buildkite และ CICD