มาดำดิ่งสู่ Cypress เพื่อการทดสอบแบบ End-to-End
เผยแพร่แล้ว: 2022-03-10บทความนี้ได้รับการสนับสนุนโดยเพื่อนรักของเราที่ LambdaTest ซึ่งกำลังทำให้ประสบการณ์การทดสอบข้ามเบราว์เซอร์ราบรื่นขึ้นสำหรับผู้คนจำนวนมากทั่วโลก ขอขอบคุณ!
การพัฒนาซอฟต์แวร์โดยไม่ใช้การทดสอบอัตโนมัติเป็นเรื่องยากที่จะจินตนาการได้ในปัจจุบัน ขั้นตอนการทดสอบต่างๆ ที่หลากหลายจะช่วยรับประกันคุณภาพในระดับสูง เป็นพื้นฐานสำหรับการทดสอบ เราสามารถใช้การทดสอบหน่วยจำนวนหนึ่งได้ ยิ่งไปกว่านั้น ตรงกลางของปิรามิดนั้นเป็นการทดสอบการรวมเข้าด้วยกัน การทดสอบแบบ end-to-end อยู่ที่ระดับบนสุด ครอบคลุมกรณีการใช้งานที่สำคัญที่สุด การทดสอบประเภทที่สามนี้จะเป็นจุดสนใจของบทความนี้
อย่างไรก็ตาม การทดสอบแบบ end-to-end มีข้อผิดพลาดบางประการ ที่ทำให้เกิดความกังวล:
- การทดสอบแบบ end-to-end นั้นช้า ดังนั้นจึงเป็นอุปสรรคสำคัญในทุกกลยุทธ์การผสานรวมอย่างต่อเนื่องและการปรับใช้อย่างต่อเนื่อง (CI/CD) ไม่เพียงแค่นั้น แต่ลองจินตนาการว่าการทำงาน คุณลักษณะ หรือการใช้งานอื่นๆ เสร็จสิ้น การรอการทดสอบดำเนินการอาจทำให้ทุกคนหมดความอดทน
- การทดสอบแบบ end-to-end ดังกล่าวยากต่อการบำรุงรักษา เกิดข้อผิดพลาดได้ง่าย และมีราคาแพงในทุกวิถีทางเนื่องจากการพยายามแก้ไขจุดบกพร่อง ปัจจัยต่าง ๆ อาจทำให้เกิดสิ่งนี้ การทดสอบของคุณควรรู้สึกเหมือนเป็นผู้ช่วย ไม่เป็นอุปสรรค
- ฝันร้ายที่ใหญ่ที่สุดสำหรับนักพัฒนาคือการทดสอบที่ไม่สม่ำเสมอ ซึ่งเป็นการทดสอบที่ดำเนินการในลักษณะเดียวกัน แต่นำไปสู่ผลลัพธ์ที่แตกต่างกัน มันเหมือนกับ “Heisenbug” ซึ่งจะเกิดขึ้นหากคุณไม่ได้วัดแอปพลิเคชันที่กำลังทดสอบ นั่นคือถ้าคุณไม่ดู
แต่อย่ากังวล: คุณไม่จำเป็นต้องยอมจำนนต่อข้อผิดพลาดเหล่านี้ เรามาดูวิธีการป้องกันหลายๆ อย่างกัน อย่างไรก็ตาม ฉันจะไม่เพียงแค่สัญญากับดวงจันทร์และไม่ส่งมอบ ในคู่มือนี้ เราจะเขียนการทดสอบร่วมกัน ซึ่งเราได้เผยแพร่ให้กับคุณในที่เก็บ GitHub ด้วยวิธีนี้ ฉันหวังว่าจะแสดงให้คุณเห็นว่าการทดสอบ end-end เป็นเรื่องสนุก! มาเริ่มกันเลย.
การทดสอบแบบ End-to-End คืออะไร?
เมื่อพูดถึงการทดสอบแบบ end-to-end (หรือ E2E) ฉันชอบที่จะเรียกว่าเป็น "ตามเวิร์กโฟลว์" วลีนี้สรุปผลการทดสอบแบบ end-to-end ได้ดี: จำลองเวิร์กโฟลว์ของผู้ใช้จริงและควรรวมพื้นที่การทำงานและส่วนต่าง ๆ ของสแต็กเทคโนโลยีที่ใช้ในแอปพลิเคชันให้มากที่สุด ในที่สุดคอมพิวเตอร์ก็ปลอมตัวเป็นลูกค้าและพยายามทำตัวเหมือนผู้ใช้จริง การทดสอบเหล่านี้เหมาะที่สุดสำหรับการใช้ความเค้นคงที่กับทั้งระบบของแอปพลิเคชันของคุณ ดังนั้นจึง เป็นการวัดที่ยอดเยี่ยมในการรับรองคุณภาพ เมื่อมีแอปพลิเคชันสแต็กทั้งหมด
มาระลึกว่าเราต้องการบรรลุอะไรจากทั้งหมดนี้ เราทราบดีว่าการทดสอบส่วนหน้าเป็นชุดแนวทางปฏิบัติสำหรับการทดสอบ UI ของเว็บแอปพลิเคชัน ซึ่งรวมถึงฟังก์ชันการทำงานด้วย สมเหตุสมผล ด้วยมาตรการเหล่านี้ เราจึงมั่นใจได้ว่าแอปพลิเคชันของเราทำงานอย่างถูกต้องและจะไม่มีการเปลี่ยนแปลงใดๆ ในอนาคตที่จะทำลายโค้ดของเรา เพื่อให้บรรลุสิ่งนี้อย่างมีประสิทธิภาพ คุณอาจสงสัยว่าต้องทดสอบอะไรและมากน้อยเพียงใด
นี่เป็นคำถามที่ถูกต้อง คุณอาจพบคำตอบที่เป็นไปได้ในคำอุปมา: ปิรามิดระบบอัตโนมัติสำหรับการทดสอบ ซึ่งเปิดตัวครั้งแรกโดย Mike Cohn และระบุเพิ่มเติมโดย Martin Fowler แสดง วิธีทำให้การทดสอบมีประสิทธิภาพ เราพบการทดสอบหน่วยที่รวดเร็วและราคาถูกที่ระดับพีระมิดที่ต่ำที่สุด และการทดสอบ UI ที่ใช้เวลานานและมีราคาแพง (การทดสอบแบบ end-to-end) ที่ด้านบน
การอธิบายสิ่งนี้และข้อดีและข้อเสียก็เพียงพอแล้วสำหรับบทความของตัวเอง ฉันต้องการเน้นในระดับหนึ่ง การทดสอบแบบ end-to-end โดยเฉพาะสามารถนำมาปรับปรุงคุณภาพได้อย่างมากหากจัดลำดับความสำคัญอย่างมีประสิทธิภาพ ในการทำเช่นนั้น เราสามารถทำให้ระบบของเราอยู่ภายใต้ความเครียดได้อย่างต่อเนื่อง และทำให้แน่ใจว่าฟังก์ชันหลักของแอปพลิเคชันของเราทำงานอย่างถูกต้อง
การเดินทางของฉันสู่ Cypress
เมื่อฉันเริ่มเรียนรู้วิธีเขียนการทดสอบแบบ end-to-end ฉันใช้ Mink ซึ่งเป็นไลบรารี PHP ที่ด้านบนของ Behat ซึ่งเป็นเฟรมเวิร์กการพัฒนาที่ขับเคลื่อนโดยพฤติกรรมตามสถานการณ์ (BDD) ฉันเริ่มใช้ซีลีเนียมโดยมีข้อดีและข้อเสียทั้งหมด เนื่องจากทีมของฉันเริ่มทำงานกับ Vue.js เป็นจำนวนมาก เราจึงเปลี่ยนไปใช้เฟรมเวิร์กการทดสอบที่ใช้ JavaScript เพื่อให้แน่ใจว่ามีการผสานรวมและเข้ากันได้อย่างไม่มีที่ติ ตัวเลือกของเราในตอนนั้นคือ Nightwatch.js ดังนั้นฉันจึงสร้างชุดทดสอบใหม่ตั้งแต่ต้น
ในช่วงเวลานี้ เรามักพบปัญหาความเข้ากันได้ คุณสามารถเรียกมันว่า การพึ่งพาอาศัยกัน — ไม่ต้องพูดถึงข้อจำกัดทั้งหมดที่เราเห็นใน Selenium และในภายหลังด้วย WebDriver
- ในทีมของเรา เราไม่สามารถตรึง CI เวอร์ชัน Chrome ของเราได้ ดังนั้น หากมีการอัปเดต Chrome ออกมา Nightwatch.js ไม่เร็วพอที่จะเข้ากันได้ ทำให้เกิดความล้มเหลวมากมายในไปป์ไลน์การทดสอบของเรา
- จำนวนสาเหตุด้านทดสอบของการทดสอบที่ไม่สม่ำเสมอเริ่มเพิ่มขึ้น เนื่องจากความเป็นไปได้ในการรอของ Nightwatch.js ไม่ตรงกับผลิตภัณฑ์ของเราอย่างเหมาะสมที่สุด
ดังนั้นเราจึงมาพิจารณาสร้างชุดทดสอบของเราใหม่ หลังจากเยี่ยมชมการประชุม ฉันก็พบ Cypress
Cypress เป็นเฟรมเวิร์กการทดสอบแบบ all-in-one ที่ไม่ใช้ Selenium หรือ WebDriver เครื่องมือนี้ใช้ Node.js เพื่อเริ่มเบราว์เซอร์ภายใต้การควบคุมพิเศษ การทดสอบในเฟรมเวิร์กนี้ทำงานในระดับเบราว์เซอร์ ไม่ใช่แค่การควบคุมจากระยะไกล ที่มีข้อดีหลายประการ
กล่าวโดยย่อ นี่คือเหตุผลที่ฉันเลือกเฟรมเวิร์กนี้:
- ความสามารถในการดีบักที่ยอดเยี่ยม
ตัวดำเนินการทดสอบของ Cypress สามารถย้อนกลับไปยังสถานะใดก็ได้ของแอปพลิเคชันผ่านสแนปชอต ดังนั้นเราจึงสามารถเห็นข้อผิดพลาดและขั้นตอนทั้งหมดก่อนหน้านั้นได้โดยตรง นอกจากนี้ยังมีการเข้าถึงเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของ Chrome (DevTools) อย่างเต็มรูปแบบ และการคลิกจะได้รับการบันทึกอย่างสมบูรณ์ - วิธีที่ดีกว่าในการรอการดำเนินการในการทดสอบหรือ UI หรือในการตอบกลับจาก API
Cypress ทำให้เกิดการรอโดยปริยาย ดังนั้นจึงไม่จำเป็นต้องมีการตรวจสอบที่เหมาะสม คุณยังทำให้การทดสอบรอภาพเคลื่อนไหวและการตอบสนอง API ได้อีกด้วย - การทดสอบเขียนด้วยจาวาสคริปต์
สิ่งนี้ช่วยลดเส้นโค้งการเรียนรู้ในการเขียนการทดสอบ ตัวดำเนินการทดสอบของ Cypress เป็นโอเพ่นซอร์ส ดังนั้นจึงเหมาะกับกลยุทธ์ผลิตภัณฑ์ของเรา
อย่างไรก็ตาม บทความนี้เป็นเพียงแนวทาง ดังนั้นเรามาหยุดที่ข้อมูลทั่วไปและไปต่อกันดีกว่า
เริ่มต้น
ติดตั้งและเริ่ม Cypress
เริ่มจากศูนย์กันก่อน ในการพูดของฉันเกี่ยวกับ Cypress ฉันมักจะเริ่มต้นด้วยการสร้างไดเร็กทอรีใหม่ผ่าน mkdir
แล้วติดตั้ง Cypress ทันที วิธีที่ง่ายที่สุดในการติดตั้งแสดงในภาพวาดนี้:
คำแนะนำเล็กน้อย: หากคุณไม่ต้องการใช้ npm คุณสามารถติดตั้ง Cypress ผ่าน Yarn:
yarn add cypress --dev
ทางเลือกอื่นคือการดาวน์โหลดโดยตรง โดยใช้โฟลเดอร์ ZIP ที่ Cypress จัดเตรียมให้ แค่นั้นแหละ! เมื่อการติดตั้งเสร็จสิ้น คุณก็พร้อมที่จะเริ่มต้น
มีสองวิธีในการเริ่มการทดสอบ Cypress อย่างแรกคือการเริ่ม Cypress ในคอนโซล และรันการทดสอบของคุณแบบไม่มีส่วนหัว:
./node_modules/.bin/cypress run
วิธีที่สองคือการใช้หนึ่งในคุณสมบัติที่เรียบร้อยของ Cypress ซึ่งเป็นตัวดำเนินการทดสอบแบบรวม ผู้ทดสอบคือ UI สำหรับการเรียกใช้การทดสอบ ในการเปิดใช้งาน คุณสามารถใช้คำสั่งที่คล้ายกัน:
./node_modules/.bin/cypress open
คำสั่งนี้จะเปิดตัวดำเนินการทดสอบ เมื่อคุณเปิด Cypress เป็นครั้งแรก คุณจะเห็นอินเทอร์เฟซนี้:
Cypress มีตัวอย่างการทดสอบที่เขียนไว้ล่วงหน้าเพื่อแสดงคุณลักษณะต่างๆ และให้จุดเริ่มต้นแก่คุณ นี่คือเหตุผลสำหรับการทดสอบที่มีอยู่ ละเลยสิ่งเหล่านั้นไปก่อน เพราะเราต้องการเขียนของเราเองในไม่ช้า อย่างไรก็ตาม โปรดคำนึงถึงส่วน "การทดสอบการรวมระบบ" นี้ไว้ เพราะจะอธิบายความมหัศจรรย์มากมายที่จะเกิดขึ้นในภายหลัง
ความประทับใจครั้งแรกของโครงสร้างของ Cypress
ตอนนี้ได้เวลาเปิดโครงการที่สร้างขึ้นใหม่ของเราในสภาพแวดล้อมการพัฒนาแบบบูรณาการ (IDE) ที่คุณเลือก หากคุณไปที่โฟลเดอร์นี้ คุณจะเห็นโครงสร้างการทดสอบต่อไปนี้:
smashing-example └── cypress └── fixtures └── integration └── plugins └── support └── cypress.json
มาดูโฟลเดอร์เหล่านี้กัน:
-
fixtures
ที่นี่คุณจะพบข้อมูลการทดสอบแบบตายตัว ซึ่งไม่เกี่ยวข้องกับเอนทิตีอื่นๆ ดังนั้นจึงไม่มีการจัดเก็บ ID ไว้ที่นี่ ซึ่งสามารถเปลี่ยนแปลงได้ตามสถานะในเครื่อง -
integration
คุณจะพบการทดสอบจริงที่นี่ -
plugins
ที่นี่ คุณสามารถขยาย Cypress ไม่ว่าจะด้วยปลั๊กอิน Cypress ที่มีอยู่หรือของคุณเอง -
support
ที่นี่ คุณสามารถขยาย Cypress ได้เอง คำสั่งและผู้ช่วยของคุณเองอยู่ที่นี่ -
cypress.json
แก้ไขการกำหนดค่าที่นี่ รวมถึงสำหรับสภาพแวดล้อม
เอาล่ะ ฉันคิดว่าเราสามารถหาทางไปรอบๆ Cypress ได้แล้ว ไม่ว่าจะเป็นผู้ทำการทดสอบหรือซอร์สโค้ด แต่เราจะเริ่มต้นอย่างไร เราต้องการทดสอบอะไร
เลือกกรณีทดสอบ
การทดสอบแบบ end-to-end ทั่วไปอาจมีความซับซ้อน โดยเฉพาะอย่างยิ่งหากมีขั้นตอนมากมาย การดำเนินการด้วยตนเองจะใช้เวลามาก เนื่องจากความซับซ้อนนี้ การทดสอบ E2E จึงเป็นระบบอัตโนมัติและทำงานช้าได้ยาก เป็นผลให้เราจำเป็นต้องตัดสินใจอย่างรอบคอบว่ากรณีใดที่จะทำให้เป็นอัตโนมัติ
ในความคิดของฉัน คำว่า "ตามเวิร์กโฟลว์" เป็นกุญแจสำคัญ : เราจะเลือกกรณีทดสอบตามเรื่องราวของผู้ใช้ทั่วไป อย่างไรก็ตาม เนื่องจากเวลาทำงาน จึงไม่แนะนำให้ครอบคลุมทุกเวิร์กโฟลว์ที่มีอยู่ ดังนั้นเราจึงต้องการวิธีจัดลำดับความสำคัญของกรณีทดสอบของเรา
ในทีมของฉัน เรามีเกณฑ์หลายประการสำหรับโครงการของเรา กรณีทดสอบควร:
- ครอบคลุมเวิร์กโฟลว์ทั่วไปและใช้มากที่สุดของฟีเจอร์ เช่น การดำเนินการ CRUD (คำว่า "เส้นทางแห่งความสุข" อธิบายเวิร์กโฟลว์เหล่านี้ได้ค่อนข้างดี)
- ใช้การวิเคราะห์ความเสี่ยง ครอบคลุมเวิร์กโฟลว์ด้วยการทดสอบ E2E ที่มีความเสี่ยงมากที่สุด (เช่น ข้อผิดพลาดจะก่อให้เกิดความเสียหายมากที่สุด)
- หลีกเลี่ยงความคุ้มครองที่ซ้ำกัน
- ไม่จำเป็นต้องใช้หากการทดสอบหน่วยมีความเหมาะสมมากกว่า (ใช้การทดสอบ E2E เพื่อทดสอบการตอบสนองของซอฟต์แวร์ของคุณต่อข้อผิดพลาด ไม่ใช่ตัวข้อผิดพลาดเอง)
สิ่งสำคัญที่สุดอันดับสองที่ต้องจำไว้คือการทดสอบเวิร์กโฟลว์ที่คุณต้องการทดสอบอย่างชัดแจ้งเท่านั้น ขั้นตอนอื่นๆ ทั้งหมดที่จำเป็นในการทำให้การทดสอบของคุณควรเสร็จสิ้นด้วยการดำเนินการ API นอกการทดสอบ เพื่อหลีกเลี่ยงการทดสอบ ด้วยวิธีนี้ คุณจะมั่นใจได้ถึงเวลารันการทดสอบที่น้อยที่สุด และได้ผลลัพธ์ที่ชัดเจนของกรณีทดสอบของคุณหากล้มเหลว คิดว่าเวิร์กโฟลว์นี้เหมือนกับผู้ใช้ปลายทาง: เน้นที่การใช้คุณลักษณะมากกว่าการใช้งานทางเทคนิค
ตัวอย่าง:
หากคุณต้องการทดสอบกระบวนการเช็คเอาต์ในร้านค้าออนไลน์ อย่าทำตามขั้นตอนอื่นๆ ทั้งหมด เช่น การสร้างสินค้าและหมวดหมู่ แม้ว่าคุณจะต้องการให้พวกเขาดำเนินการชำระเงินก็ตาม ตัวอย่างเช่น ใช้ API หรือดัมพ์ฐานข้อมูลเพื่อสร้างสิ่งเหล่านี้ และกำหนดค่าการทดสอบสำหรับการชำระเงินเท่านั้น
ตัวอย่าง: การค้นหาบทความของฉันใน Smashing Magazine
ฉันต้องการเขียนแบบทดสอบสำหรับเว็บไซต์นี้ Smashing Magazine ฉันไม่สามารถรับรองได้ว่าการทดสอบนี้จะเป็นปัจจุบันตลอดไป แต่หวังว่าการทดสอบนี้จะคงอยู่ตลอดไป ไม่ว่าจะด้วยวิธีใด คุณจะพบตัวอย่างนี้ในที่เก็บ GitHub
สร้างการทดสอบ Cypress ครั้งแรกของเรา
ในโฟลเดอร์ integration
เราจะเริ่มต้นด้วยการสร้างไฟล์ใหม่ เรียกมัน find-author.spec.js
คำต่อท้าย .spec ย่อมาจาก “ .spec
” ในแง่ของการทดสอบ หมายถึงรายละเอียดทางเทคนิคของคุณลักษณะหรือแอปพลิเคชันที่กำหนดซึ่งแอปพลิเคชันของคุณจะต้องปฏิบัติตาม
ในการเปลี่ยนไฟล์ JavaScript ที่ว่างเปล่านี้เป็นหน้าแรกของการทดสอบ เราจะเริ่มต้นด้วยการกำหนดโครงสร้างของชุดการทดสอบ เราจะใช้วิธีที่เรียกว่า describe
describe()
หรือ context()
ใช้เพื่อบรรจุและจัดระเบียบการทดสอบ กล่าวอีกนัยหนึ่ง วิธีนี้ทำหน้าที่เป็นกรอบสำหรับการทดสอบของเรา ดังนั้น ไฟล์ทดสอบของเราจะมีลักษณะดังนี้:
// find-author.spec.js describe('Find authors at smashing', () => { //... });
ขั้นตอนต่อไปคือการสร้างการทดสอบจริง เราจะใช้วิธี it
it()
หรือ specify()
ใช้เพื่อแสดงถึงการทดสอบจริง อย่างที่คุณเห็น เราสามารถบันทึกการทดสอบหลายรายการในไฟล์เดียว ซึ่งช่วยให้มีตัวเลือกการจัดโครงสร้างที่ยอดเยี่ยม
// find-author.spec.js describe('Find authors at smashing', () => { it('Find the author Ramona Schwering', () => { cy.log('This is our brand-new test'); }); });
คำแนะนำเล็กน้อย : หากคุณคุ้นเคยกับ Mocha คุณอาจสังเกตเห็นความคล้ายคลึงกันบางอย่าง Cypress สร้างขึ้นบน Mocha ดังนั้นไวยากรณ์จึงเหมือนกัน
เอาล่ะ ไปกันเลย หากเราทำการทดสอบในโปรแกรมทดสอบของ Cypress เราจะสังเกตเห็นว่า Cypress จะเปิดเบราว์เซอร์เพื่อทำการทดสอบ เบราว์เซอร์นี้มีให้เห็นในภาพหน้าจอด้านล่าง:
ยินดีด้วย! เราได้เขียนการทดสอบครั้งแรกของเรา! แน่นอนว่ามันไม่ได้ช่วยอะไรมาก เราจำเป็นต้องดำเนินการต่อ มาเติมบททดสอบด้วยชีวิตกันเถอะ
เติมบททดสอบด้วยชีวิต
สิ่งแรกที่ต้องทำเมื่อทดสอบเว็บไซต์คืออะไร ถูกต้อง เราต้องเปิดเว็บไซต์ เราสามารถทำได้โดยใช้คำสั่ง Cypress คำสั่งคืออะไรคุณอาจสงสัย?
การทำงานกับคำสั่ง
คำแนะนำส่วนใหญ่ที่ใช้ในการทดสอบ E2E มี 2 ประเภท คำสั่งประเภทแรก คำสั่ง หมายถึงแต่ละขั้นตอนในการทดสอบ ในบริบทของ Cypress คำสั่งคือทุกสิ่งที่ Cypress ทำเพื่อโต้ตอบกับเว็บไซต์ของคุณ การโต้ตอบนี้อาจเป็นอะไรก็ได้ ไม่ว่าจะเป็นการคลิก การเลื่อนดูเว็บไซต์ หรือแม้แต่การค้นหาองค์ประกอบ ด้วยเหตุนี้ คำสั่งจึงเป็นหนึ่งในสิ่งสำคัญที่เราจะใช้ในการทดสอบ
ดังนั้น คำสั่งแรกของเราคือคำสั่งที่นำทางไปยังเว็บไซต์ — smashingmagazine.com
คำสั่งนี้เรียกว่า visit
เมื่อใช้การทดสอบของเราจะมีลักษณะดังนี้:
// find-author.spec.js describe('Find authors at smashing', () => { it('Find the author Ramona Schwering', () => { cy.visit('https://www.smashingmagazine.com/'); }); });
มีคำสั่งหนึ่งที่ฉันใช้บ่อย – และคุณก็จะทำเช่นกัน เรียกว่า get
:
cy.get('selector');
คำสั่งนี้ส่งคืนองค์ประกอบตามตัวเลือก - คล้ายกับ $(…)
ของ jQuery ดังนั้น คุณจะใช้คำสั่งนี้เพื่อค้นหาส่วนต่างๆ ที่จะโต้ตอบด้วย โดยปกติ คุณจะใช้มันเพื่อเริ่มชุดคำสั่ง แต่เดี๋ยวก่อน - สายการบังคับบัญชาหมายถึงอะไร?
ดังที่กล่าวไว้ในตอนต้นของบทความนี้ การทดสอบทั้งหมดและทุกอย่างอื่นที่เกี่ยวข้องนั้นเขียนด้วย JavaScript คุณสามารถใส่คำสั่งในการทดสอบ (เช่นคำสั่ง) ในห่วงโซ่ (กล่าวอีกนัยหนึ่ง) ซึ่งหมายความว่าคำสั่งสามารถส่งผ่านเรื่อง (หรือคืนค่า) ของคำสั่งไปยังคำสั่งต่อไปนี้ ตามที่เราทราบจากกรอบการทดสอบจำนวนมาก
เอาล่ะ เราจะเริ่มชุดคำสั่งด้วยคำสั่ง get
ในการค้นหาองค์ประกอบด้วย get
เราต้องหาตัวเลือกก่อน การค้นหาตัวเลือกเฉพาะเป็นสิ่งสำคัญ เนื่องจาก Cypress จะคืนค่าองค์ประกอบที่ตรงกันทั้งหมด ดังนั้น พึงระลึกไว้เสมอและหลีกเลี่ยงหากเกิดขึ้นโดยไม่ได้ตั้งใจ
โต้ตอบกับองค์ประกอบ
Cypress มีคุณสมบัติที่จะช่วยคุณค้นหาตัวเลือกขององค์ประกอบที่คุณต้องการใช้งาน คุณลักษณะนี้เรียกว่า Selector Playground และช่วยให้คุณค้นพบตัวเลือกเฉพาะของส่วนประกอบหรือเพื่อดูองค์ประกอบที่ตรงกันทั้งหมดสำหรับตัวเลือกหรือสตริงข้อความ ดังนั้น คุณลักษณะนี้สามารถช่วยคุณได้มากในงานนี้ หากต้องการเปิดใช้งาน เพียงคลิกไอคอนเป้าเล็งในส่วนหัวของ UI ของการทดสอบ แล้ววางเมาส์เหนือองค์ประกอบที่ต้องการ:
ตามที่เห็นในภาพหน้าจอด้านบน คำแนะนำเครื่องมือจะแสดงตัวเลือกเมื่อวางเมาส์เหนือหรือในแถบเล็กๆ นี้ใต้ไอคอนเป้า ซึ่งปรากฏขึ้นเมื่อองค์ประกอบถูกคลิก ในแถบนี้ คุณยังสามารถดูจำนวนองค์ประกอบที่จะจับคู่กับตัวเลือกที่กำหนด ซึ่งทำให้มั่นใจได้ถึงความเป็นเอกลักษณ์ในกรณีของเรา
บางครั้ง ตัวเลือกที่สร้างขึ้นโดยอัตโนมัติเหล่านั้นอาจไม่ใช่ตัวเลือกที่คุณต้องการใช้ (เช่น ตัวเลือกยาวหรืออ่านยาก หรือไม่ตรงตามเกณฑ์อื่นๆ ของคุณ) ตัวเลือกที่สร้างขึ้นด้านล่างนั้นยากต่อการทำความเข้าใจและยาวเกินไปในความเห็นที่ต่ำต้อยของฉัน:
ในกรณีนี้ ฉันจะกลับไปใช้ DevTools ของเบราว์เซอร์เพื่อค้นหาตัวเลือกเฉพาะของฉัน คุณอาจคุ้นเคยกับเครื่องมือเหล่านี้ ในกรณีของฉัน ฉันมักจะเลือก Chrome เพื่อจุดประสงค์นี้ อย่างไรก็ตาม เบราว์เซอร์ที่รองรับอื่นๆ อาจมีคุณสมบัติที่คล้ายคลึงกัน กระบวนการนี้ให้ความรู้สึกคล้ายกับ Selector Playground เว้นแต่ว่าเรากำลังใช้คุณสมบัติของ DevTools ในแท็บ "องค์ประกอบ"
เพื่อให้แน่ใจว่าตัวเลือกจะไม่ซ้ำกัน ฉันขอแนะนำให้ค้นหาในมุมมองโค้ดของ DevTools หากคุณพบผลลัพธ์เพียงรายการเดียว คุณสามารถมั่นใจได้ว่าผลลัพธ์นั้นไม่ซ้ำใคร
คุณรู้หรือไม่ว่า ซีเล็คเตอร์มีหลายประเภท ? การทดสอบอาจมีลักษณะและทำงานค่อนข้างแตกต่างไปจากเดิมอย่างสิ้นเชิง ทั้งนี้ขึ้นอยู่กับความหลากหลาย บางพันธุ์เหมาะสำหรับการทดสอบแบบ end-to-end มากกว่ารุ่นอื่นๆ หากคุณต้องการทราบว่าตัวเลือกใดที่จะใช้เพื่อให้การทดสอบของคุณมีความเสถียรและสะอาด ฉันสามารถแนะนำบทความของฉันที่ครอบคลุมปัญหานี้ให้คุณได้ นักพัฒนาของ Cypress เองได้ให้คำแนะนำเกี่ยวกับหัวข้อนี้ในแนวทางปฏิบัติที่ดีที่สุด
การทดสอบของเราเป็นลำดับของคำสั่ง
ตกลงกลับไปที่การทดสอบของเรา ในนั้น เราต้องการแสดงเวิร์กโฟลว์ของเรา:
“ในฐานะผู้ใช้ ฉันจะค้นหาบทความของผู้เขียนและไปที่เว็บไซต์ของผู้เขียนผ่านพื้นที่อ้างอิงในบทความของพวกเขา”
เราจะทำซ้ำขั้นตอนที่ผู้ใช้จะทำโดยใช้คำสั่ง ฉันจะวางด้านล่างการทดสอบเสร็จสิ้นพร้อมความคิดเห็น ซึ่งจะอธิบายขั้นตอนต่างๆ:
// find-author.spec.js it('Find the author Ramona Schwering', () => { // Open the website cy.visit('https://www.smashingmagazine.com'); // Enter author's name in search field cy.get('#js-search-input').type('Ramona Schwering'); // Navigate to author's article cy.get('h2 > a').first().click(); // Open the author's page cy.get('.author-post__author-title').click(); });
ตัวอย่างนี้เกี่ยวข้องกับเวิร์กโฟลว์ที่เราต้องการทดสอบ Cypress จะดำเนินการทดสอบนี้ ถึงเวลากล่าวคำว่า "ยินดีด้วย" แล้วหรือยัง? ในที่สุดเราก็เขียนการทดสอบครั้งแรกเสร็จแล้วหรือยัง?
ได้โปรด มอง ให้ละเอียดยิ่งขึ้น Cypress จะดำเนินการ แต่จะทำตามที่การทดสอบบอกเท่านั้น ซึ่งเป็นสิ่งที่คุณเขียน หากคุณเรียกใช้ในนักวิ่งทดสอบ คุณจะเห็นว่าผ่านหรือไม่ แต่ไม่ใช่ในกรณีที่คุณวิ่งอย่างหัวเสีย จากการทดสอบนี้ เรารู้เพียงว่า Cypress สามารถเรียกใช้คำสั่งของเราได้สำเร็จหรือไม่ ไม่ใช่ว่าเราลงเอยที่เว็บไซต์ของผู้เขียนหรือไม่ ดังนั้น เราต้องสอนการทดสอบของเราเพื่อตรวจสอบว่า
การทำงานกับการยืนยัน
คำสั่งประเภทที่สองดูแลคำอธิบายของสถานะที่ต้องการของ UI นั่นคือ ไม่ว่าบางสิ่งควรมีอยู่ มองเห็นได้ หรือไม่ปรากฏอีกต่อไป การยืนยันใน Cypress ขึ้นอยู่กับการยืนยันของ Chai และ Sinon-Chai ซึ่งสังเกตได้ชัดเจนในไวยากรณ์
จำไว้ว่าเราต้องการตรวจสอบว่าเราอยู่ในหน้าโปรไฟล์ของผู้เขียนหรือไม่ — ของฉันในตัวอย่างนี้ ดังนั้น เราต้องเพิ่มคำยืนยันให้แน่ชัดว่า:
// find-author.spec.js it('Find the author Ramona Schwering', () => { // Open the website cy.visit('https://www.smashingmagazine.com'); // Enter author's name in search field cy.get('#js-search-input').type('Ramona Schwering'); // Navigate to author's article cy.get('h2 > a').first().click(); // Open the author's page cy.get('.author-post__author-title').click(); // Check if we're on the author's site cy.contains('.author__title', 'Ramona Schwering').should('be.visible'); });
เอาล่ะ ตอนนี้เราได้เขียนการทดสอบที่มีค่าแล้ว ใช่ ขอแสดงความยินดีกับการเขียนการทดสอบครั้งแรกของคุณ... แม้ว่าจะยังไม่สมบูรณ์แบบก็ตาม
มาทำให้การทดสอบของเราสวยขึ้น
แม้ว่าเราจะประสบความสำเร็จในการเขียนการทดสอบที่มีความหมายครั้งแรกและได้เรียนรู้แนวคิดหลักในกระบวนการนี้ ฉันก็ยังไม่รวมการทดสอบนี้หากมันถูกเสนอในคำขอดึง เหลืออีกสองสามสิ่งที่ต้องทำเพื่อให้มันเปล่งประกาย
ใช้เวลาของคุณ
Cypress มีตัวเลือกการลองใหม่ในตัวในเกือบทุกคำสั่ง ดังนั้นคุณจึงไม่ต้องรอดูว่ามีองค์ประกอบอยู่แล้ว ตัวอย่างเช่น อย่างไรก็ตาม นี่เป็นเพียงการดูว่าองค์ประกอบนั้นมีอยู่ใน DOM หรือไม่ ไม่เกินนั้น Cypress ไม่สามารถคาดเดาทุกอย่างที่แอปพลิเคชันของคุณทำ ดังนั้นอาจมีความไม่แน่นอนอยู่บ้างหากคุณพึ่งพาสิ่งนี้เพียงอย่างเดียว
ผู้ใช้จะทำอย่างไรหากพวกเขาต้องการเห็นเว็บไซต์ที่ยังโหลดอยู่ พวกเขามักจะรอจนกว่าบางส่วนของเว็บไซต์จะมองเห็นได้ (ดังนั้น โหลดแล้ว) และโต้ตอบกับพวกเขา ในการทดสอบของเรา เราต้องการเลียนแบบอย่างแม่นยำว่า: เราต้องการ รอการเปลี่ยนแปลงใน UI ก่อนที่จะเริ่มโต้ตอบ ในกรณีส่วนใหญ่ เราจะจำกัดพฤติกรรมนี้ไว้ที่องค์ประกอบที่เราต้องการ ดังนั้นจึงใช้การยืนยันกับองค์ประกอบเหล่านั้น
อย่างที่คุณเห็น เราต้องรอการทดสอบหลายครั้ง อย่างไรก็ตามการรอหลายครั้งเกินไปก็ไม่ดีเช่นกัน ตามกฎทั่วไป ฉันขอแนะนำให้ใช้การยืนยันเพื่อตรวจสอบว่าองค์ประกอบที่จะโต้ตอบมีการโหลดอย่างสมบูรณ์หรือไม่ ซึ่งเป็นขั้นตอนแรกในการพิจารณาว่าเว็บไซต์ที่กำลังทดสอบโหลดหรือไม่
ลองดูส่วนหนึ่งของการทดสอบของเราเป็นตัวอย่าง ฉันได้เพิ่มการยืนยันหนึ่งรายการเพื่อ ให้แน่ใจว่าหน้าของเราโหลดเต็มแล้ว :
// find-author-assertions.spec.js // Open website cy.visit('https://www.smashingmagazine.com'); // Ensure site is fully loaded cy.get('.headline-content').should('be.visible'); // Enter author's name in the search field cy.get('#js-search-input').type('Ramona Schwering');
ให้เพิ่มการยืนยันในลักษณะดังกล่าวกับทุกกรณีที่เว็บไซต์ของเราจะมีเวลาในการโหลดหรือองค์ประกอบหลายอย่างที่ต้องแสดงผลใหม่ สำหรับไฟล์ทดสอบที่สมบูรณ์ โปรดดูที่การทดสอบที่เกี่ยวข้องในที่เก็บ GitHub
เพื่อหลีกเลี่ยงไม่ให้ตกหลุมพรางของการทดสอบที่ไม่สม่ำเสมอ ฉันอยากจะบอกใบ้สุดท้ายกับคุณ: อย่าใช้เวลารอแบบตายตัว เช่น cy.wait(500)
หรืออื่นๆ ที่คล้ายกัน
การตอบสนอง API คือเพื่อนของคุณ
มีความเป็นไปได้อย่างหนึ่งในการรอโดยเฉพาะอย่างยิ่งที่ฉันชอบใช้ในการทดสอบของฉัน ใน Cypress คุณสามารถทำงานกับคุณลักษณะเครือข่ายได้ — อีกวิธีหนึ่งที่เป็นประโยชน์ในการรอในแอปพลิเคชันของคุณคือการ ใช้คุณสมบัติเหล่านี้เพื่อทำงานกับคำขอของเครือข่าย ด้วยวิธีนี้ คุณสามารถทำให้การทดสอบรอการตอบกลับ API ที่สำเร็จได้
หากเราจำเวิร์กโฟลว์ของเราเป็นตัวอย่างได้ ขั้นตอนเดียวอาจใช้ความเป็นไปได้ในการรอ API ได้อย่างดีเยี่ยม ฉันกำลังคิดเกี่ยวกับการค้นหา เรื่องราวของผู้ใช้ที่เกี่ยวข้องอาจเป็นดังนี้:
“ฉันในฐานะนักพัฒนาซอฟต์แวร์ต้องการให้แน่ใจว่าผลการค้นหาของเราโหลดเต็มแล้ว เพื่อไม่ให้บทความของผลลัพธ์ที่เก่ากว่าจะทำให้การทดสอบของเราเข้าใจผิด”
ลองใช้สิ่งนั้นกับการทดสอบของเรา อันดับแรก เราต้องกำหนดเส้นทางที่เราต้องการรอในภายหลัง เราสามารถใช้คำสั่ง intercept
สำหรับสิ่งนี้ ฉันจะค้นหาคำขอโดยนำข้อมูลที่ฉันต้องการ – ผลการค้นหาในกรณีนี้
เพื่อให้ตัวอย่างนี้ง่ายขึ้น ฉันจะใช้สัญลักษณ์แทนสำหรับ URL หลังจากนั้น ฉันจะใช้นามแฝงเพื่อให้ Cypress สามารถทำงานกับเส้นทางนี้ได้ในภายหลัง
// find-author-hooks.spec.js // Set the route to work with it('Find the author Ramona Schwering', () => { // Route to wait for later cy.intercept({ url: '*/indexes/smashingmagazine/*', method: 'POST' }).as('search'); // With this alias Cypress will find the request again //...
ใน Cypress เส้นทางที่กำหนดทั้งหมดจะแสดงที่จุดเริ่มต้นของการทดสอบ ดังนั้น ฉันอยากจะใส่คำสั่ง intercept
เหล่านั้นไว้ที่จุดเริ่มต้นของการทดสอบของฉันด้วย
ตอนนี้ เราสามารถใช้นามแฝงของเส้นทางนี้ในการยืนยันได้ วิธีที่ง่ายที่สุดในการทำเช่นนี้คือใช้คำสั่ง wait
ของ Cypress โดยใช้นามแฝงที่กล่าวถึงก่อนหน้านี้โดยตรง อย่างไรก็ตาม การใช้คำสั่งนี้เพียงอย่างเดียวอาจนำไปสู่การ รอการตอบสนองโดยไม่คำนึงถึงผลลัพธ์ แม้แต่รหัสข้อผิดพลาด เช่น 400 หรือ 500 ก็นับว่าผ่าน ในขณะที่แอปพลิเคชันของคุณมักจะใช้งานไม่ได้ ดังนั้นฉันขอแนะนำให้เพิ่มการยืนยันอื่นเช่นนี้:
// find-author-hooks.spec.js // Later: Assertion of the search request's status code cy.wait('@search') .its('response.statusCode').should('equal', 200);
ด้วยวิธีนี้ เราจึงสามารถรอข้อมูลของซอฟต์แวร์ การเปลี่ยนแปลง และอื่นๆ ได้อย่างแม่นยำ โดยไม่ต้องเสียเวลาหรือเกิดปัญหาหากแอปพลิเคชันได้รับความเครียดอย่างหนัก อีกครั้ง คุณสามารถค้นหาไฟล์ตัวอย่างทั้งหมดได้ในที่เก็บ GitHub ของฉัน
การกำหนดค่า Cypress
ฉันได้ละทิ้งรายละเอียดเล็กๆ ไปหนึ่งอย่าง หากคุณพิจารณาตัวอย่างการทดสอบฉบับสมบูรณ์อย่างละเอียดถี่ถ้วน จะแตกต่างจากตัวอย่างที่เราใช้ในคู่มือนี้เล็กน้อย
// Cypress describe('Find author at smashing', () => { beforeEach(() => { // Open website cy.visit('https://www.smashingmagazine.com'); }); //...
ฉันใช้สแลชเพื่อเปิดเว็บไซต์ของนิตยสาร Smashing เท่านั้น มันทำงานอย่างไร? การใช้คำสั่งแบบนี้จะนำทางไปยัง baseUrl
ของการทดสอบของเรา baseUrl
เป็นค่าคอนฟิกูเรชันที่สามารถใช้เป็นคำนำหน้าสำหรับ URL ของคำสั่ง cy.visit()
หรือ cy.request()
ในบรรดาค่าอื่นๆ เราสามารถกำหนดค่านี้ได้ในไฟล์ cypress.json
สำหรับการทดสอบของเรา เราจะตั้งค่า baseUrl
ดังนี้:
// cypress.json { "baseUrl": "https://www.smashingmagazine.com" }
รางวัลชมเชย: Hooks
เหลืออีกหัวข้อหนึ่งที่ฉันอยากจะพูดถึง แม้ว่าการทดสอบตัวอย่างของเราจะไม่เหมาะกับการใช้งานก็ตาม ตามปกติในเฟรมเวิร์กการทดสอบอื่นๆ เราสามารถกำหนดสิ่งที่เกิดขึ้นก่อนและหลังการทดสอบของเราผ่านสิ่งที่เรียกว่า lifecycle hooks แม่นยำยิ่งขึ้น สิ่งเหล่านี้มีอยู่เพื่อรันโค้ดก่อนหรือหลังการทดสอบหนึ่งหรือทั้งหมด:
// Cypress describe('Hooks', function() { before(() => { // Runs once before all tests }); after(() => { // Runs once after all tests }); beforeEach(() => { // Runs before each test }); afterEach(() => { // Runs after each test }); });
เราต้องการเติมไฟล์ทดสอบของเราด้วยการทดสอบมากกว่าหนึ่งรายการ ดังนั้นเราควรมองหาขั้นตอนทั่วไปที่เราต้องการดำเนินการก่อนหรือหลังการทดสอบ บรรทัดแรกของเราเป็นกรณีตัวอย่าง คือ คำสั่งการ visit
สมมติว่าเราต้องการเปิดเว็บไซต์นี้ก่อนการทดสอบแต่ละครั้ง a beforeEach
hook ในตัวอย่างของเราจะมีลักษณะดังนี้:
// Cypress describe('Find author at smashing', () => { beforeEach(() => { // Open website cy.visit('https://www.smashingmagazine.com'); }); //...
ฉันมักจะใช้สิ่งนี้ในงานประจำวันของฉันเพื่อให้แน่ใจว่าแอปพลิเคชันของฉันถูก รีเซ็ตเป็นสถานะเริ่มต้นก่อนการทดสอบ ดังนั้นจึงแยกการทดสอบออกจากการทดสอบอื่นๆ ( อย่าพึ่งการทดสอบก่อนหน้านี้! ) เรียกใช้การทดสอบของคุณแยกจากกันเพื่อคงการควบคุมสถานะของแอปพลิเคชัน
การทดสอบแต่ละครั้งควรสามารถดำเนินการได้ด้วยตัวเอง — โดยไม่ขึ้นกับการทดสอบอื่นๆ นี้เป็นสิ่งสำคัญเพื่อ ให้แน่ใจว่าผลการทดสอบที่ถูกต้อง สำหรับรายละเอียดเกี่ยวกับเรื่องนี้ โปรดดูที่ส่วน “ข้อมูลที่เราใช้ในการแบ่งปัน” ในบทความล่าสุดของฉัน สำหรับตอนนี้ ให้ดูตัวอย่างที่สมบูรณ์บน GitHub หากคุณต้องการดูการทดสอบทั้งหมด
บทสรุป
ในความเห็นของฉัน การทดสอบแบบ end-to-end เป็นองค์ประกอบสำคัญของ CI ทำให้คุณภาพของแอปพลิเคชันอยู่ในระดับสูง และในขณะเดียวกันก็ช่วยลดการทำงานของผู้ทดสอบ Cypress เป็นเครื่องมือที่ฉันเลือกสำหรับการดีบักการทดสอบแบบ end-to-end อย่างรวดเร็ว เสถียร และมีประสิทธิภาพ และสำหรับการรันแบบขนานกับคำขอดึงใดๆ ซึ่งเป็นส่วนหนึ่งของ CI เส้นโค้งการเรียนรู้นั้นไม่ซับซ้อน หากคุณคุ้นเคยกับ JavaScript อยู่แล้ว
ฉันหวังว่าฉันจะสามารถแนะนำคุณได้เล็กน้อยและเป็นจุดเริ่มต้นในการเขียนการทดสอบ Cypress และคำแนะนำที่เป็นประโยชน์ในการเริ่มต้น แน่นอน ตัวอย่างโค้ดทั้งหมดมีอยู่ในที่เก็บ GitHub ดังนั้นลองดูตามสบาย
แน่นอนว่านี่เป็นเพียงจุดเริ่มต้นเท่านั้น มีหลายสิ่งให้เรียนรู้และหารือเกี่ยวกับการทดสอบ Cypress ฉันจะฝากคำแนะนำเกี่ยวกับสิ่งที่ต้องเรียนรู้ต่อไปให้คุณ เมื่อคำนึงถึงสิ่งนี้ ขอให้มีความสุขในการทดสอบ!
ทรัพยากร
- ตัวอย่างยอดเยี่ยมดั้งเดิม Ramona Schwering
ที่เก็บ GitHub สำหรับตัวอย่างในบทความนี้ - เอกสาร Cypress
- “สูตรอาหาร”, Cypress
การเลือกตัวอย่าง สูตรอาหาร และหลักสูตร - “เรียนรู้การเขียนโค้ดด้วย JavaScript: Cypress” (บทเรียน), CodeLikeThis
- แนวทางปฏิบัติที่ดีที่สุดในการเขียนการทดสอบตั้งแต่ต้นจนจบ”, Shopware Docs