ไม้โปรแทรกเตอร์ - คู่มือฉบับย่อ
บทนี้ให้ข้อมูลเบื้องต้นเกี่ยวกับไม้โปรแทรกเตอร์ซึ่งคุณจะได้เรียนรู้เกี่ยวกับที่มาของกรอบการทดสอบนี้และเหตุใดคุณจึงต้องเลือกสิ่งนี้การทำงานและข้อ จำกัด ของเครื่องมือนี้
ไม้โปรแทรกเตอร์คืออะไร?
Protractor เป็นกรอบการทดสอบแบบ end-to-end แบบโอเพนซอร์สสำหรับแอปพลิเคชัน Angular และ AngularJS Google สร้างขึ้นที่ด้านบนของ WebDriver นอกจากนี้ยังทำหน้าที่แทนกรอบการทดสอบ AngularJS E2E ที่มีอยู่ซึ่งเรียกว่า“ Angular Scenario Runner”
นอกจากนี้ยังทำงานเป็นผู้รวมโซลูชันที่รวมเทคโนโลยีอันทรงพลังเช่น NodeJS, Selenium, Jasmine, WebDriver, Cucumber, Mocha เป็นต้นนอกจากการทดสอบแอปพลิเคชัน AngularJS แล้วยังเขียนการทดสอบการถดถอยอัตโนมัติสำหรับเว็บแอปพลิเคชันปกติ ช่วยให้เราสามารถทดสอบแอปพลิเคชันของเราได้เหมือนกับผู้ใช้จริงเนื่องจากรันการทดสอบโดยใช้เบราว์เซอร์จริง
แผนภาพต่อไปนี้จะให้ภาพรวมคร่าวๆของไม้โปรแทรกเตอร์ -
สังเกตว่าในแผนภาพด้านบนเรามี -
Protractor - ตามที่กล่าวไว้ก่อนหน้านี้มันเป็นกระดาษห่อหุ้มบน WebDriver JS ที่ออกแบบมาโดยเฉพาะสำหรับแอปเชิงมุม
Jasmine- โดยพื้นฐานแล้วเป็นกรอบการพัฒนาที่ขับเคลื่อนด้วยพฤติกรรมสำหรับการทดสอบโค้ด JavaScript เราสามารถเขียนข้อสอบได้ง่ายๆด้วยจัสมิน
WebDriver JS - เป็นการใช้งานการผูก Node JS สำหรับซีลีเนียม 2.0 / WebDriver
Selenium - เพียงแค่เปิดเบราว์เซอร์โดยอัตโนมัติ
แหล่งกำเนิด
ดังที่ได้กล่าวไว้ก่อนหน้านี้ Protractor ใช้แทนกรอบการทดสอบ AngularJS E2E ที่มีอยู่ซึ่งเรียกว่า“ Angular Scenario Runner” โดยพื้นฐานแล้วต้นกำเนิดของไม้โปรแทรกเตอร์เริ่มต้นด้วยจุดสิ้นสุดของ Scenario Runner คำถามที่เกิดขึ้นคือทำไมเราต้องสร้าง Protractor? เพื่อให้เข้าใจสิ่งนี้ก่อนอื่นเราต้องตรวจสอบเกี่ยวกับรุ่นก่อน - Scenario Runner
การเริ่มต้นของไม้โปรแทรกเตอร์
Julie Ralph ผู้สนับสนุนหลักในการพัฒนา Protractor มีประสบการณ์ต่อไปนี้กับ Angular Scenario Runner ในโครงการอื่น ๆ ภายใน Google สิ่งนี้กลายเป็นแรงจูงใจในการสร้างไม้โปรแทรกเตอร์โดยเฉพาะเพื่อเติมเต็มช่องว่าง -
“ เราลองใช้ Scenario Runner และพบว่ามันไม่สามารถทำสิ่งที่เราต้องการทดสอบได้จริงๆ เราจำเป็นต้องทดสอบสิ่งต่างๆเช่นการเข้าสู่ระบบหน้าเข้าสู่ระบบของคุณไม่ใช่หน้าเชิงมุมและ Scenario Runner ไม่สามารถจัดการกับสิ่งนั้นได้ และมันไม่สามารถจัดการกับสิ่งต่างๆเช่นป๊อปอัปและหลาย ๆ หน้าต่างการนำทางประวัติเบราว์เซอร์อะไรทำนองนั้น”
ข้อได้เปรียบที่ใหญ่ที่สุดสำหรับ Protractor คือการครบกำหนดของโครงการ Selenium และได้สรุปวิธีการต่างๆเพื่อให้สามารถใช้สำหรับโครงการ Angular ได้อย่างง่ายดาย การออกแบบไม้โปรแทรกเตอร์สร้างขึ้นในลักษณะที่ทดสอบเลเยอร์ทั้งหมดเช่น UI ของเว็บบริการแบ็กเอนด์เลเยอร์การคงอยู่และอื่น ๆ ของแอปพลิเคชัน
ทำไมต้องเป็นไม้โปรแทรกเตอร์
อย่างที่เราทราบกันดีว่าแอปพลิเคชันเกือบทั้งหมดใช้ JavaScript ในการพัฒนา งานของผู้ทดสอบจะยากขึ้นเมื่อ JavaScript มีขนาดเพิ่มขึ้นและมีความซับซ้อนสำหรับแอปพลิเคชันเนื่องจากจำนวนแอปพลิเคชันที่เพิ่มขึ้น ส่วนใหญ่การจับองค์ประกอบของเว็บในแอปพลิเคชัน AngularJS นั้นยากมากโดยใช้ไวยากรณ์ HTML แบบขยายเพื่อแสดงส่วนประกอบของเว็บแอปพลิเคชันโดยใช้ JUnit หรือ Selenium WebDriver
คำถามคือเหตุใด Selenium Web Driver จึงไม่พบองค์ประกอบของเว็บ AngularJS? สาเหตุเป็นเพราะแอปพลิเคชัน AngularJS มีแอตทริบิวต์ HTML เพิ่มเติมเช่น ng-repeater, ng-controller และ ng-model เป็นต้นซึ่งไม่รวมอยู่ในตัวระบุตำแหน่งซีลีเนียม
ที่นี่ความสำคัญของไม้โปรแทรกเตอร์เกิดขึ้นได้เนื่องจากไม้โปรแทรกเตอร์ที่อยู่ด้านบนของซีลีเนียมสามารถจัดการและควบคุมองค์ประกอบ HTML เพิ่มเติมเหล่านั้นในเว็บแอปพลิเคชัน AngularJS นั่นคือเหตุผลที่เราสามารถพูดได้ว่าเฟรมเวิร์กส่วนใหญ่มุ่งเน้นไปที่การทดสอบหน่วยสำหรับแอปพลิเคชัน AngularJS ไม้โปรแทรกเตอร์ใช้ในการทดสอบการทำงานจริงของแอปพลิเคชัน
การทำงานของไม้โปรแทรกเตอร์
Protractor ซึ่งเป็นกรอบการทดสอบทำงานร่วมกับ Selenium เพื่อจัดเตรียมโครงสร้างพื้นฐานการทดสอบอัตโนมัติสำหรับจำลองการโต้ตอบของผู้ใช้กับแอปพลิเคชัน AngularJS ที่ทำงานในเบราว์เซอร์หรืออุปกรณ์เคลื่อนที่
สามารถเข้าใจการทำงานของไม้โปรแทรกเตอร์ได้ด้วยความช่วยเหลือของขั้นตอนต่อไปนี้ -
Step 1- ในขั้นตอนแรกเราต้องเขียนแบบทดสอบ สามารถทำได้ด้วยความช่วยเหลือของจัสมินหรือมอคค่าหรือแตงกวา
Step 2- ตอนนี้เราต้องทำการทดสอบซึ่งสามารถทำได้ด้วยความช่วยเหลือของไม้โปรแทรกเตอร์ เรียกอีกอย่างว่านักวิ่งทดสอบ
Step 3 - ในขั้นตอนนี้เซิร์ฟเวอร์ Selenium จะช่วยจัดการเบราว์เซอร์
Step 4 - ในที่สุด API ของเบราว์เซอร์จะถูกเรียกใช้ด้วยความช่วยเหลือของ Selenium WebDriver
ข้อดี
กรอบการทดสอบแบบ end-to-end แบบโอเพนซอร์สนี้มีข้อดีดังต่อไปนี้ -
Protractor เป็นเครื่องมือโอเพ่นซอร์สนั้นง่ายต่อการติดตั้งและตั้งค่า
ทำงานได้ดีกับกรอบจัสมินเพื่อสร้างแบบทดสอบ
รองรับการทดสอบขับเคลื่อนการพัฒนา (TDD)
มีการรออัตโนมัติซึ่งหมายความว่าเราไม่จำเป็นต้องเพิ่มการรอและการนอนหลับอย่างชัดเจนในการทดสอบของเรา
นำเสนอข้อดีทั้งหมดของ Selenium WebDriver
รองรับการทดสอบแบบขนานผ่านเบราว์เซอร์หลายตัว
ให้ประโยชน์ของการซิงโครไนซ์อัตโนมัติ
มีความเร็วในการทดสอบที่ยอดเยี่ยม
ข้อ จำกัด
กรอบการทดสอบ end-to-end แบบโอเพนซอร์สนี้มีข้อ จำกัด ดังต่อไปนี้ -
ไม่เปิดเผยแนวดิ่งใด ๆ ในระบบอัตโนมัติของเบราว์เซอร์เนื่องจากเป็น Wrapper สำหรับ WebDriver JS
ความรู้เกี่ยวกับ JavaScript เป็นสิ่งสำคัญสำหรับผู้ใช้เนื่องจากมีให้สำหรับ JavaScript เท่านั้น
ให้การทดสอบส่วนหน้าเท่านั้นเนื่องจากเป็นเครื่องมือทดสอบที่ขับเคลื่อนด้วย UI
เนื่องจากความรู้เกี่ยวกับ JavaScript เป็นสิ่งจำเป็นสำหรับการทำงานกับ Protractor ในบทนี้ให้เราเข้าใจแนวคิดของการทดสอบ JavaScript โดยละเอียด
การทดสอบ JavaScript และระบบอัตโนมัติ
JavaScript เป็นภาษาสคริปต์ที่พิมพ์และตีความแบบไดนามิกที่ได้รับความนิยมมากที่สุด แต่งานที่ท้าทายที่สุดคือการทดสอบโค้ด เนื่องจากไม่เหมือนกับภาษาคอมไพล์อื่น ๆ เช่น JAVA และ C ++ ไม่มีขั้นตอนการคอมไพล์ใน JavaScript ที่สามารถช่วยผู้ทดสอบในการหาข้อผิดพลาดได้ นอกจากนี้การทดสอบบนเบราว์เซอร์ยังใช้เวลานานมาก ดังนั้นจึงมีความจำเป็นสำหรับเครื่องมือที่รองรับการทดสอบอัตโนมัติสำหรับ JavaScript
แนวคิดของการทดสอบอัตโนมัติ
การเขียนแบบทดสอบเป็นแนวทางปฏิบัติที่ดีเสมอเพราะจะทำให้โค้ดดีขึ้น ปัญหาในการทดสอบด้วยตนเองคือใช้เวลานานเล็กน้อยและเกิดข้อผิดพลาดได้ง่าย กระบวนการทดสอบด้วยตนเองค่อนข้างน่าเบื่อสำหรับโปรแกรมเมอร์เช่นกันเนื่องจากต้องทำซ้ำขั้นตอนเขียนข้อกำหนดการทดสอบเปลี่ยนรหัสและรีเฟรชเบราว์เซอร์หลาย ๆ ครั้ง นอกจากนี้การทดสอบด้วยตนเองยังทำให้กระบวนการพัฒนาช้าลง
เนื่องจากเหตุผลข้างต้นจึงมีประโยชน์เสมอที่จะมีเครื่องมือบางอย่างที่สามารถทำให้การทดสอบเหล่านี้เป็นไปโดยอัตโนมัติและช่วยโปรแกรมเมอร์ในการกำจัดขั้นตอนที่ซ้ำซากและน่าเบื่อเหล่านี้ นักพัฒนาควรทำอย่างไรเพื่อให้กระบวนการทดสอบเป็นไปโดยอัตโนมัติ
โดยทั่วไปนักพัฒนาสามารถใช้ชุดเครื่องมือใน CLI (Command Line Interpreter) หรือใน IDE การพัฒนา (สภาพแวดล้อมการพัฒนาแบบบูรณาการ) จากนั้นการทดสอบเหล่านี้จะทำงานอย่างต่อเนื่องในกระบวนการแยกต่างหากแม้ว่าจะไม่มีข้อมูลจากนักพัฒนาก็ตาม การทดสอบ JavaScript อัตโนมัตินั้นไม่ใช่เรื่องใหม่และมีการพัฒนาเครื่องมือมากมายเช่น Karma, Protractor, CasperJS เป็นต้น
ประเภทของการทดสอบ JavaScript
อาจมีการทดสอบที่แตกต่างกันสำหรับวัตถุประสงค์ที่แตกต่างกัน ตัวอย่างเช่นการทดสอบบางอย่างถูกเขียนขึ้นเพื่อตรวจสอบลักษณะการทำงานของฟังก์ชันในโปรแกรมในขณะที่การทดสอบอื่น ๆ เขียนขึ้นเพื่อทดสอบการไหลของโมดูลหรือคุณลักษณะ ดังนั้นเราจึงมีการทดสอบสองประเภทดังต่อไปนี้ -
การทดสอบหน่วย
การทดสอบจะทำในส่วนที่เล็กที่สุดที่ทดสอบได้ของโปรแกรมที่เรียกว่าหน่วย โดยทั่วไปแล้วหน่วยได้รับการทดสอบแบบแยกส่วนโดยไม่มีการพึ่งพาหน่วยนั้นกับส่วนอื่น ๆ ในกรณีของ JavaScript แต่ละเมธอดหรือฟังก์ชันที่มีลักษณะการทำงานเฉพาะอาจเป็นหน่วยของโค้ดและต้องทดสอบหน่วยของโค้ดเหล่านี้ด้วยวิธีแยก
ข้อดีอย่างหนึ่งของการทดสอบหน่วยคือการทดสอบหน่วยสามารถทำได้ตามลำดับใด ๆ เนื่องจากหน่วยเป็นอิสระจากกัน ข้อดีอีกอย่างของการทดสอบหน่วยซึ่งนับได้ว่าสามารถเรียกใช้การทดสอบได้ตลอดเวลาดังนี้ -
- ตั้งแต่เริ่มต้นกระบวนการพัฒนา
- หลังจากเสร็จสิ้นการพัฒนาโมดูล / คุณสมบัติใด ๆ
- หลังจากแก้ไขโมดูล / คุณสมบัติใด ๆ
- หลังจากเพิ่มคุณสมบัติใหม่ในแอปพลิเคชันที่มีอยู่
สำหรับการทดสอบหน่วยอัตโนมัติของแอปพลิเคชัน JavaScript เราสามารถเลือกจากเครื่องมือและกรอบการทดสอบมากมายเช่น Mocha, Jasmine และ QUnit
การทดสอบแบบ end-to-End
อาจกำหนดให้เป็นวิธีการทดสอบที่ใช้เพื่อทดสอบว่าขั้นตอนของแอปพลิเคชันตั้งแต่ต้นจนจบ (จากปลายด้านหนึ่งไปยังอีกด้านหนึ่ง) ทำงานได้ดีตามการออกแบบหรือไม่
การทดสอบแบบ end-to-end เรียกอีกอย่างว่าการทดสอบฟังก์ชัน / การไหล ซึ่งแตกต่างจากการทดสอบหน่วยการทดสอบแบบ end-to-end จะทดสอบว่าส่วนประกอบแต่ละส่วนทำงานร่วมกันเป็นแอปพลิเคชันอย่างไร นี่คือข้อแตกต่างที่สำคัญระหว่างการทดสอบหน่วยและการทดสอบแบบ end-to-end
ตัวอย่างเช่นสมมติว่าหากเรามีโมดูลการลงทะเบียนที่ผู้ใช้จำเป็นต้องให้ข้อมูลที่ถูกต้องเพื่อทำการลงทะเบียนให้เสร็จสมบูรณ์การทดสอบ E2E สำหรับโมดูลนั้นจะทำตามขั้นตอนต่อไปนี้เพื่อทำการทดสอบให้เสร็จสมบูรณ์ -
- ขั้นแรกมันจะโหลด / คอมไพล์ฟอร์มหรือโมดูล
- ตอนนี้จะได้รับ DOM (Document object model) ขององค์ประกอบของฟอร์ม
- จากนั้นทริกเกอร์เหตุการณ์การคลิกของปุ่มส่งเพื่อตรวจสอบว่าใช้งานได้หรือไม่
- ตอนนี้เพื่อวัตถุประสงค์ในการตรวจสอบให้รวบรวมค่าจากช่องป้อนข้อมูล
- ถัดไปควรตรวจสอบช่องป้อนข้อมูล
- เพื่อจุดประสงค์ในการทดสอบให้เรียก API ปลอมเพื่อจัดเก็บข้อมูล
ทุกขั้นตอนให้ผลลัพธ์ของตัวเองซึ่งจะนำไปเปรียบเทียบกับผลลัพธ์ที่คาดหวังไว้
ตอนนี้คำถามที่เกิดขึ้นคือในขณะที่ E2E หรือการทดสอบการทำงานประเภทนี้สามารถทำได้ด้วยตนเองทำไมเราถึงต้องการระบบอัตโนมัติสำหรับสิ่งนี้? เหตุผลหลักคือระบบอัตโนมัติจะทำให้กระบวนการทดสอบนี้ง่าย เครื่องมือที่มีอยู่บางตัวที่สามารถรวมเข้ากับแอปพลิเคชันใด ๆ ได้อย่างง่ายดายเพื่อจุดประสงค์นี้ ได้แก่ Selenium, PhantomJS และ Protractor
เครื่องมือและกรอบการทดสอบ
เรามีเครื่องมือและกรอบการทดสอบต่างๆสำหรับการทดสอบเชิงมุม ต่อไปนี้เป็นเครื่องมือและกรอบการทำงานที่รู้จักกันดี -
กรรม
กรรมสร้างโดย Vojta Jina เป็นนักวิ่งทดสอบ เดิมโครงการนี้เรียกว่า Testacular ไม่ใช่กรอบการทดสอบซึ่งหมายความว่าช่วยให้เราสามารถเรียกใช้การทดสอบหน่วย JavaScript บนเบราว์เซอร์จริงได้อย่างง่ายดายและโดยอัตโนมัติ Karma ถูกสร้างขึ้นสำหรับ AngularJS เนื่องจากก่อนหน้านี้ Karma ไม่มีเครื่องมือทดสอบอัตโนมัติสำหรับนักพัฒนา JavaScript บนเว็บ ในทางกลับกันด้วยระบบอัตโนมัติที่ Karma จัดเตรียมไว้ให้นักพัฒนาสามารถเรียกใช้คำสั่งง่ายๆเพียงคำสั่งเดียวและกำหนดว่าชุดทดสอบทั้งหมดผ่านหรือล้มเหลว
ข้อดีของการใช้ Karma
ต่อไปนี้เป็นข้อดีบางประการของการใช้ Karma เมื่อเปรียบเทียบกับกระบวนการด้วยตนเอง -
- ทำการทดสอบโดยอัตโนมัติในหลายเบราว์เซอร์และอุปกรณ์ต่างๆ
- ตรวจสอบไฟล์เพื่อหาข้อผิดพลาดและแก้ไข
- ให้การสนับสนุนออนไลน์และเอกสาร
- ง่ายต่อการรวมกับเซิร์ฟเวอร์การรวมแบบต่อเนื่อง
จุดด้อยของการใช้กรรม
สิ่งต่อไปนี้เป็นข้อเสียของการใช้ Karma -
ข้อเสียเปรียบหลักของการใช้ Karma คือต้องใช้เครื่องมือเพิ่มเติมในการกำหนดค่าและบำรุงรักษา
หากคุณใช้ Karma test runner กับ Jasmine จะมีเอกสารประกอบน้อยกว่าสำหรับค้นหาข้อมูลเกี่ยวกับการตั้งค่า CSS ของคุณในกรณีที่มีหลายรหัสสำหรับองค์ประกอบเดียว
จัสมิน
Jasmine ซึ่งเป็นกรอบการพัฒนาที่ขับเคลื่อนด้วยพฤติกรรมสำหรับการทดสอบโค้ด JavaScript ได้รับการพัฒนาที่ Pivotal Labs ก่อนที่จะมีการพัฒนาจัสมินเฟรมเวิร์คเฟรมเวิร์กการทดสอบหน่วยที่คล้ายกันที่ชื่อ JsUnit ได้รับการพัฒนาโดย Pivotal Labs ซึ่งมีตัวทดสอบในตัว การทดสอบเบราว์เซอร์สามารถเรียกใช้ผ่านการทดสอบของจัสมินโดยรวมไฟล์ SpecRunner.html หรือโดยใช้เป็นตัวดำเนินการทดสอบบรรทัดคำสั่งด้วย สามารถใช้ได้ทั้งแบบมีหรือไม่มี Karma ก็ได้
ข้อดีของการใช้ดอกมะลิ
ต่อไปนี้เป็นข้อดีของการใช้ Jasmine -
กรอบงานที่เป็นอิสระจากเบราว์เซอร์แพลตฟอร์มและภาษา
รองรับการพัฒนาที่ขับเคลื่อนด้วยการทดสอบ (TDD) พร้อมกับการพัฒนาที่ขับเคลื่อนด้วยพฤติกรรม
มีการรวมเข้ากับ Karma เป็นค่าเริ่มต้น
ไวยากรณ์ที่เข้าใจง่าย
ให้สายลับทดสอบของปลอมและฟังก์ชันการส่งผ่านซึ่งช่วยในการทดสอบเป็นฟังก์ชันเพิ่มเติม
จุดด้อยของการใช้ดอกมะลิ
ต่อไปนี้เป็นข้อเสียของการใช้ Jasmine -
การทดสอบจะต้องส่งคืนโดยผู้ใช้เมื่อมีการเปลี่ยนแปลงเนื่องจากไม่มีคุณสมบัติการดูไฟล์ในจัสมินขณะดำเนินการทดสอบ
มอคค่า
Mocha เขียนขึ้นสำหรับแอปพลิเคชัน Node.js เป็นกรอบการทดสอบ แต่ยังรองรับการทดสอบเบราว์เซอร์ มันค่อนข้างเหมือนจัสมิน แต่ความแตกต่างที่สำคัญระหว่างพวกเขาคือ Mocha ต้องการปลั๊กอินและไลบรารีเนื่องจากไม่สามารถรันแบบสแตนด์อโลนเป็นกรอบการทดสอบได้ ในทางกลับกันจัสมินเป็นแบบสแตนด์อโลน อย่างไรก็ตามมอคค่ามีความยืดหยุ่นในการใช้งานมากกว่าจัสมิน
ข้อดีของการใช้มอคค่า
ต่อไปนี้เป็นข้อดีบางประการของการใช้ Mocha -
- Mocha ติดตั้งและกำหนดค่าได้ง่ายมาก
- เอกสารที่ใช้งานง่ายและเรียบง่าย
- ประกอบด้วยปลั๊กอินที่มีโครงการโหนดหลายโครงการ
จุดด้อยของการใช้มอคค่า
ต่อไปนี้เป็นข้อเสียของการใช้ Mocha -
- ต้องการโมดูลแยกต่างหากสำหรับการยืนยันสายลับ ฯลฯ
- นอกจากนี้ยังต้องมีการกำหนดค่าเพิ่มเติมเพื่อใช้กับ Karma
QUnit
QUint เดิมพัฒนาโดย John Resig ในปี 2008 โดยเป็นส่วนหนึ่งของ jQuery เป็นชุดทดสอบหน่วย JavaScript ที่มีประสิทธิภาพและใช้งานง่าย สามารถใช้ทดสอบโค้ด JavaScript ทั่วไปได้ แม้ว่าจะเน้นไปที่การทดสอบ JavaScript ในเบราว์เซอร์ แต่ผู้พัฒนาก็ใช้งานได้สะดวกมาก
ข้อดีของการใช้ QUnit
ต่อไปนี้เป็นข้อดีบางประการของการใช้ QUnit -
- ติดตั้งและกำหนดค่าได้ง่าย
- เอกสารที่ใช้งานง่ายและเรียบง่าย
จุดด้อยของการใช้ QUnit
ต่อไปนี้เป็นข้อเสียของการใช้ QUnit -
- ส่วนใหญ่ได้รับการพัฒนาสำหรับ jQuery และด้วยเหตุนี้จึงไม่เหมาะสำหรับใช้กับเฟรมเวิร์กอื่น ๆ
ซีลีเนียม
ซีลีเนียมซึ่งพัฒนาโดย Jason Huggins ในปี 2547 เป็นเครื่องมือภายในที่ ThoughtWorks เป็นเครื่องมือทดสอบอัตโนมัติแบบโอเพนซอร์ส ซีลีเนียมนิยามตัวเองว่า“ ซีลีเนียมเบราว์เซอร์อัตโนมัติ แค่นั้นแหละ!". การทำงานอัตโนมัติของเบราว์เซอร์หมายความว่านักพัฒนาสามารถโต้ตอบกับเบราว์เซอร์ได้อย่างง่ายดาย
ข้อดีของการใช้ซีลีเนียม
ต่อไปนี้เป็นข้อดีบางประการของการใช้ซีลีเนียม -
- ประกอบด้วยชุดคุณสมบัติขนาดใหญ่
- รองรับการทดสอบแบบกระจาย
- มีการสนับสนุน SaaS ผ่านบริการต่างๆเช่น Sauce Labs
- ใช้งานง่ายด้วยเอกสารที่เรียบง่ายและทรัพยากรที่มีอยู่มากมาย
จุดด้อยของการใช้ซีลีเนียม
ต่อไปนี้เป็นข้อเสียบางประการของการใช้ซีลีเนียม -
- ข้อเสียเปรียบหลักของการใช้ซีลีเนียมคือต้องเรียกใช้เป็นกระบวนการแยกต่างหาก
- การกำหนดค่าค่อนข้างยุ่งยากเนื่องจากนักพัฒนาต้องทำตามขั้นตอนต่างๆ
ในบทก่อนหน้านี้เราได้เรียนรู้พื้นฐานของไม้โปรแทรกเตอร์ ในบทนี้ให้เราเรียนรู้วิธีการติดตั้งและกำหนดค่า
ข้อกำหนดเบื้องต้น
เราจำเป็นต้องปฏิบัติตามข้อกำหนดเบื้องต้นต่อไปนี้ก่อนที่จะติดตั้ง Protractor บนคอมพิวเตอร์ของคุณ -
โหนด js
Protractor เป็นโมดูล Node.js ดังนั้นข้อกำหนดเบื้องต้นที่สำคัญมากคือเราต้องติดตั้ง Node.js ไว้ในคอมพิวเตอร์ของเรา เราจะติดตั้งแพ็กเกจ Protractor โดยใช้ npm (โปรแกรมจัดการแพ็คเกจ JavaScript) ที่มาพร้อมกับ Node.js
สำหรับการติดตั้ง Node.js โปรดไปที่ลิงค์ทางการ - https://nodejs.org/en/download/. หลังจากติดตั้ง Node.js คุณสามารถตรวจสอบเวอร์ชันของ Node.js และ npm ได้โดยเขียนคำสั่งnode --version และ npm --version ในพรอมต์คำสั่งดังที่แสดงด้านล่าง -
โครเมียม
Google Chrome ซึ่งเป็นเว็บเบราว์เซอร์ที่ Google สร้างขึ้นจะใช้เพื่อเรียกใช้การทดสอบแบบ end-to-end ใน Protractor โดยไม่ต้องใช้เซิร์ฟเวอร์ Selenium คุณสามารถดาวน์โหลด chrome ได้โดยคลิกที่ลิงค์ -https://www.google.com/chrome/.
Selenium WebDriver สำหรับ Chrome
เครื่องมือนี้มาพร้อมกับโมดูล Protractor npm และช่วยให้เราสามารถโต้ตอบกับเว็บแอปพลิเคชัน
การติดตั้งไม้โปรแทรกเตอร์
หลังจากติดตั้ง Node.js บนคอมพิวเตอร์ของเราแล้วเราสามารถติดตั้ง Protractor ได้โดยใช้คำสั่งต่อไปนี้ -
npm install -g protractor
เมื่อติดตั้งไม้โปรแทรกเตอร์สำเร็จเราสามารถตรวจสอบเวอร์ชันได้โดยการเขียน protractor --version คำสั่งในพรอมต์คำสั่งดังที่แสดงด้านล่าง -
การติดตั้ง WebDriver สำหรับ Chrome
หลังจากติดตั้ง Protractor เราจำเป็นต้องติดตั้ง Selenium WebDriver สำหรับ Chrome สามารถติดตั้งได้ด้วยความช่วยเหลือของคำสั่งต่อไปนี้ -
webdriver-manager update
คำสั่งดังกล่าวจะสร้างไดเร็กทอรี Selenium ซึ่งมีไดรเวอร์ Chrome ที่จำเป็นซึ่งใช้ในโครงการ
การยืนยันการติดตั้งและการกำหนดค่า
เราสามารถยืนยันการติดตั้งและกำหนดค่าของ Protractor ได้โดยทำการเปลี่ยนแปลง Conf.js ที่ให้ไว้ในตัวอย่างเล็กน้อยหลังจากติดตั้ง Protractor คุณสามารถค้นหาไฟล์ conf.js นี้ในไดเร็กทอรีรูทnode_modules/Protractor/example.
ขั้นแรกให้สร้างไฟล์ใหม่ชื่อ testingconfig.js ในไดเร็กทอรีเดียวกันคือ node_modules/Protractor/example.
ตอนนี้ในไฟล์ conf.js ภายใต้พารามิเตอร์การประกาศไฟล์ต้นทางให้เขียน testingconfig.js
จากนั้นบันทึกและปิดไฟล์ทั้งหมดและเปิดพรอมต์คำสั่ง เรียกใช้ไฟล์ conf.js ดังที่แสดงในภาพหน้าจอด้านล่าง
การกำหนดค่าและการติดตั้ง Protractor จะสำเร็จหากคุณได้ผลลัพธ์ตามที่แสดงด้านล่าง -
ผลลัพธ์ข้างต้นแสดงให้เห็นว่าไม่มีข้อกำหนดเนื่องจากเราจัดเตรียมไฟล์ว่างไว้ที่พารามิเตอร์การประกาศไฟล์ต้นทางในไฟล์ conf.js แต่จากผลลัพธ์ข้างต้นเราจะเห็นว่าทั้งไม้โปรแทรกเตอร์และ WebDriver ทำงานได้สำเร็จ
ปัญหาในการติดตั้งและการกำหนดค่า
ขณะติดตั้งและกำหนดค่า Protractor และ WebDriver เราอาจพบปัญหาทั่วไปดังต่อไปนี้ -
ติดตั้งซีลีเนียมไม่ถูกต้อง
เป็นปัญหาที่พบบ่อยที่สุดขณะติดตั้ง WebDriver ปัญหานี้เกิดขึ้นหากคุณไม่อัปเดต WebDriver โปรดทราบว่าเราต้องอัปเดต WebDriver มิฉะนั้นเราจะไม่สามารถอ้างอิงกับการติดตั้ง Protractor ได้
ไม่พบการทดสอบ
ปัญหาที่พบบ่อยอีกประการหนึ่งคือหลังจากเรียกใช้ Protractor แสดงว่าไม่พบการทดสอบ สำหรับสิ่งนี้เราต้องตรวจสอบให้แน่ใจว่าพา ธ สัมพัทธ์ชื่อไฟล์หรือนามสกุลถูกต้อง เราต้องเขียนไฟล์ conf.js อย่างระมัดระวังเพราะมันเริ่มต้นด้วยไฟล์กำหนดค่าเอง
ตามที่กล่าวไว้ก่อนหน้านี้ Protractor เป็นกรอบการทดสอบแบบโอเพนซอร์สแบบ end-to-end สำหรับแอปพลิเคชัน Angular และ AngularJS มันคือโปรแกรม Node.js ในทางกลับกัน Selenium เป็นเฟรมเวิร์กอัตโนมัติของเบราว์เซอร์ที่มี Selenium Server, WebDriver APIs และไดรเวอร์เบราว์เซอร์ WebDriver
ไม้โปรแทรกเตอร์กับซีลีเนียม
ถ้าเราพูดถึงการทำงานร่วมกันของ Protractor และ Selenium Protractor สามารถทำงานร่วมกับเซิร์ฟเวอร์ Selenium เพื่อจัดเตรียมโครงสร้างพื้นฐานการทดสอบอัตโนมัติ โครงสร้างพื้นฐานสามารถจำลองการโต้ตอบของผู้ใช้กับแอปพลิเคชันเชิงมุมที่ทำงานในเบราว์เซอร์หรือบนอุปกรณ์เคลื่อนที่ การทำงานร่วมกันของ Protractor และ Selenium สามารถแบ่งออกเป็นสามพาร์ติชัน ได้แก่ การทดสอบเซิร์ฟเวอร์และเบราว์เซอร์ดังแสดงในแผนภาพต่อไปนี้ -
กระบวนการ Selenium WebDriver
ดังที่เราได้เห็นในแผนภาพด้านบนการทดสอบโดยใช้ Selenium WebDriver เกี่ยวข้องกับสามกระบวนการต่อไปนี้ -
- สคริปต์ทดสอบ
- เซิฟเวอร์
- เบราว์เซอร์
ในส่วนนี้ให้เราพูดคุยเกี่ยวกับการสื่อสารระหว่างกระบวนการทั้งสามนี้
การสื่อสารระหว่างสคริปต์ทดสอบและเซิร์ฟเวอร์
การสื่อสารระหว่างสองกระบวนการแรก - สคริปต์ทดสอบและเซิร์ฟเวอร์ขึ้นอยู่กับการทำงานของเซิร์ฟเวอร์ซีลีเนียม กล่าวอีกนัยหนึ่งเราสามารถพูดได้ว่าวิธีการทำงานของเซิร์ฟเวอร์ Selenium จะทำให้กระบวนการสื่อสารระหว่างสคริปต์ทดสอบและเซิร์ฟเวอร์มีรูปร่าง
เซิร์ฟเวอร์ซีลีเนียมสามารถทำงานในเครื่องของเราในรูปแบบเซิร์ฟเวอร์ซีลีเนียมแบบสแตนด์อโลน (selenium-server-standalone.jar) หรือสามารถทำงานจากระยะไกลผ่านบริการ (Sauce Labs) ในกรณีของเซิร์ฟเวอร์ Selenium แบบสแตนด์อโลนจะมีการสื่อสาร http ระหว่าง Node.js และเซิร์ฟเวอร์ซีลีเนียม
การสื่อสารระหว่างเซิร์ฟเวอร์และเบราว์เซอร์
ดังที่เราทราบว่าเซิร์ฟเวอร์มีหน้าที่ส่งต่อคำสั่งไปยังเบราว์เซอร์หลังจากตีความสิ่งเดียวกันจากสคริปต์ทดสอบ นั่นคือเหตุผลที่เซิร์ฟเวอร์และเบราว์เซอร์ต้องการสื่อการสื่อสารและที่นี่การสื่อสารทำได้ด้วยความช่วยเหลือของJSON WebDriver Wire Protocol. เบราว์เซอร์ขยายด้วย Browser Driver ที่ใช้ในการตีความคำสั่ง
แนวคิดข้างต้นเกี่ยวกับกระบวนการ Selenium WebDriver และการสื่อสารสามารถเข้าใจได้ด้วยความช่วยเหลือของแผนภาพต่อไปนี้ -
ในขณะที่ทำงานกับ Protractor กระบวนการแรกนั่นคือสคริปต์ทดสอบจะทำงานโดยใช้ Node.js แต่ก่อนที่จะดำเนินการใด ๆ กับเบราว์เซอร์จะส่งคำสั่งพิเศษเพื่อให้แน่ใจว่าแอปพลิเคชันที่กำลังทดสอบนั้นเสถียร
การตั้งค่าเซิร์ฟเวอร์ Selenium
Selenium Server ทำหน้าที่เหมือนพร็อกซีเซิร์ฟเวอร์ระหว่างสคริปต์ทดสอบของเราและไดรเวอร์เบราว์เซอร์ โดยพื้นฐานแล้วจะส่งต่อคำสั่งจากสคริปต์ทดสอบของเราไปยัง WebDriver และส่งคืนการตอบสนองจาก WebDriver ไปยังสคริปต์ทดสอบของเรา มีตัวเลือกต่อไปนี้สำหรับการตั้งค่าเซิร์ฟเวอร์ Selenium ซึ่งรวมอยู่ในconf.js ไฟล์ของสคริปต์ทดสอบ -
เซิร์ฟเวอร์ซีลีเนียมแบบสแตนด์อโลน
หากเราต้องการรันเซิร์ฟเวอร์บนเครื่องของเราเราจำเป็นต้องติดตั้งเซิร์ฟเวอร์ซีลีเนียมแบบสแตนด์อโลน ข้อกำหนดเบื้องต้นในการติดตั้งเซิร์ฟเวอร์ซีลีเนียมแบบสแตนด์อโลนคือ JDK (Java Development Kit) เราต้องติดตั้ง JDK บนเครื่องของเรา เราสามารถตรวจสอบได้โดยเรียกใช้คำสั่งต่อไปนี้จากบรรทัดคำสั่ง -
java -version
ตอนนี้เรามีตัวเลือกในการติดตั้งและเริ่ม Selenium Server ด้วยตนเองหรือจากสคริปต์ทดสอบ
การติดตั้งและเริ่มเซิร์ฟเวอร์ Selenium ด้วยตนเอง
สำหรับการติดตั้งและเริ่มเซิร์ฟเวอร์ Selenium ด้วยตนเองเราจำเป็นต้องใช้เครื่องมือบรรทัดคำสั่ง WebDriver-Manager ที่มาพร้อมกับ Protractor ขั้นตอนในการติดตั้งและเริ่มเซิร์ฟเวอร์ Selenium มีดังต่อไปนี้ -
Step 1- ขั้นตอนแรกคือการติดตั้งเซิร์ฟเวอร์ Selenium และ ChromeDriver สามารถทำได้โดยใช้คำสั่งต่อไปนี้ -
webdriver-manager update
Step 2- ต่อไปเราต้องเริ่มเซิร์ฟเวอร์ สามารถทำได้โดยใช้คำสั่งต่อไปนี้ -
webdriver-manager start
Step 3- ในที่สุดเราต้องตั้งค่า seleniumAddress ในไฟล์ config เป็นที่อยู่ของเซิร์ฟเวอร์ที่รันอยู่ ที่อยู่เริ่มต้นจะเป็นhttp://localhost:4444/wd/hub.
การเริ่มต้นเซิร์ฟเวอร์ Selenium จากสคริปต์ทดสอบ
สำหรับการเริ่มต้นเซิร์ฟเวอร์ Selenium จาก Test Script เราจำเป็นต้องตั้งค่าตัวเลือกต่อไปนี้ในไฟล์กำหนดค่าของเรา -
Location of jar file - เราจำเป็นต้องกำหนดตำแหน่งของไฟล์ jar สำหรับเซิร์ฟเวอร์ Selenium แบบสแตนด์อโลนในไฟล์ config โดยการตั้งค่า seleniumServerJar
Specifying the port- เราจำเป็นต้องระบุพอร์ตที่จะใช้เพื่อเริ่มเซิร์ฟเวอร์ Selenium แบบสแตนด์อโลน สามารถระบุในไฟล์ config โดยการตั้งค่า seleniumPort พอร์ตเริ่มต้นคือ 4444
Array of command line options- เราต้องตั้งค่าอาร์เรย์ของตัวเลือกบรรทัดคำสั่งเพื่อส่งไปยังเซิร์ฟเวอร์ สามารถระบุในไฟล์ config โดยการตั้งค่า seleniumArgs หากคุณต้องการรายการคำสั่งอาร์เรย์ทั้งหมดให้เริ่มเซิร์ฟเวอร์ด้วยคำสั่ง-help ธง.
การทำงานกับ Remote Selenium Server
อีกทางเลือกหนึ่งสำหรับการเรียกใช้การทดสอบของเราคือการใช้เซิร์ฟเวอร์ Selenium จากระยะไกล ข้อกำหนดเบื้องต้นสำหรับการใช้เซิร์ฟเวอร์จากระยะไกลคือเราต้องมีบัญชีที่มีบริการที่โฮสต์เซิร์ฟเวอร์ ในขณะที่ทำงานกับ Protractor เรามีการสนับสนุนในตัวสำหรับบริการต่อไปนี้ที่โฮสต์เซิร์ฟเวอร์ -
TestObject
สำหรับการใช้ TestObject เป็นเซิร์ฟเวอร์ Selenium ระยะไกลเราจำเป็นต้องตั้งค่า testobjectUser ชื่อผู้ใช้ของบัญชี TestObject และ testobjectKey คีย์ API ของบัญชี TestObject ของเรา
BrowserStack
สำหรับการใช้ BrowserStack เป็นเซิร์ฟเวอร์ Selenium ระยะไกลเราจำเป็นต้องตั้งค่า browserstackUser ชื่อผู้ใช้ของบัญชี BrowserStack และ browserstackKey คีย์ API ของบัญชี BrowserStack ของเรา
ซอส Labs
สำหรับการใช้ Sauce Labs เป็นเซิร์ฟเวอร์ Selenium ระยะไกลเราจำเป็นต้องตั้ง sauceUser ชื่อผู้ใช้ของบัญชี Sauce Labs ของเราและ SauceKey ซึ่งเป็นรหัส API ของบัญชี Sauce Labs ของเรา
Kobiton
สำหรับการใช้ Kobiton เป็นเซิร์ฟเวอร์ Selenium ระยะไกลเราจำเป็นต้องตั้งค่า kobitonUser ชื่อผู้ใช้ของบัญชี Kobiton และ kobitonKey คีย์ API ของบัญชี Kobiton ของเรา
เชื่อมต่อโดยตรงกับ Browser Driver โดยไม่ต้องใช้ Selenium Server
อีกหนึ่งทางเลือกสำหรับการทดสอบของเราคือการเชื่อมต่อกับ Browser Driver โดยตรงโดยไม่ต้องใช้เซิร์ฟเวอร์ Selenium Protractor สามารถทดสอบได้โดยตรงโดยไม่ต้องใช้ Selenium Server กับ Chrome และ Firefox โดยการตั้งค่า directConnect: true ในไฟล์ config
การตั้งค่าเบราว์เซอร์
ก่อนกำหนดค่าและตั้งค่าเบราว์เซอร์เราจำเป็นต้องทราบว่า Protractor รองรับเบราว์เซอร์ใดบ้าง ต่อไปนี้เป็นรายการเบราว์เซอร์ที่ Protractor รองรับ -
- ChromeDriver
- FirefoxDriver
- SafariDriver
- IEDriver
- Appium-iOS/Safari
- Appium-Android/Chrome
- Selendroid
- PhantomJS
สำหรับการตั้งค่าและกำหนดค่าเบราว์เซอร์เราจำเป็นต้องย้ายไปที่ไฟล์ config ของ Protractor เนื่องจากการตั้งค่าเบราว์เซอร์เสร็จสิ้นภายในวัตถุความสามารถของไฟล์กำหนดค่า
การตั้งค่า Chrome
สำหรับการตั้งค่าเบราว์เซอร์ Chrome เราต้องตั้งค่าวัตถุความสามารถดังนี้
capabilities: {
'browserName': 'chrome'
}
นอกจากนี้เรายังสามารถเพิ่มตัวเลือกเฉพาะของ Chrome ซึ่งซ้อนอยู่ใน chromeOptions และสามารถดูรายการทั้งหมดได้ที่ https://sites.google.com/a/chromium.org/chromedriver/capabilities.
ตัวอย่างเช่นหากคุณต้องการเพิ่มตัวนับ FPS ที่มุมขวาบนคุณสามารถทำได้ดังนี้ในไฟล์กำหนดค่า -
capabilities: {
'browserName': 'chrome',
'chromeOptions': {
'args': ['show-fps-counter=true']
}
},
การตั้งค่า Firefox
สำหรับการตั้งค่าเบราว์เซอร์ Firefox เราต้องตั้งค่าความสามารถดังต่อไปนี้ -
capabilities: {
'browserName': 'firefox'
}
นอกจากนี้เรายังสามารถเพิ่มตัวเลือกเฉพาะของ Firefox ซึ่งซ้อนอยู่ในอ็อบเจ็กต์ moz: firefoxOptions และรายการทั้งหมดสามารถดูได้ที่ https://github.com/mozilla/geckodriver#firefox-capabilities.
ตัวอย่างเช่นหากคุณต้องการเรียกใช้การทดสอบบน Firefox ในเซฟโหมดสามารถทำได้ดังต่อไปนี้ในไฟล์ config -
capabilities: {
'browserName': 'firefox',
'moz:firefoxOptions': {
'args': ['—safe-mode']
}
},
การตั้งค่าเบราว์เซอร์อื่น
สำหรับการตั้งค่าเบราว์เซอร์อื่นที่ไม่ใช่ Chrome หรือ Firefox เราจำเป็นต้องติดตั้งไบนารีแยกต่างหากจาก https://docs.seleniumhq.org/download/.
การตั้งค่า PhantonJS
จริงๆแล้ว PhantomJS ไม่ได้รับการสนับสนุนอีกต่อไปเนื่องจากปัญหาการขัดข้อง แทนที่จะแนะนำให้ใช้ Chrome แบบไม่มีหัวหรือ Firefox แบบไม่มีหัว สามารถตั้งค่าได้ดังนี้ -
สำหรับการตั้งค่า Chrome แบบไม่มีหัวเราจำเป็นต้องเริ่มต้น Chrome ด้วยการตั้งค่าสถานะไร้หัวดังนี้ -
capabilities: {
'browserName': 'chrome',
'chromeOptions': {
'args': [“--headless”, “--disable-gpu”, “--window-size=800,600”]
}
},
สำหรับการตั้งค่า Firefox แบบไม่มีหัวเราต้องเริ่ม Firefox ด้วยไฟล์ –headless ธงดังนี้ -
capabilities: {
'browserName': 'firefox',
'moz:firefoxOptions': {
'args': [“--headless”]
}
},
การตั้งค่าเบราว์เซอร์หลายตัวสำหรับการทดสอบ
นอกจากนี้เรายังสามารถทดสอบกับเบราว์เซอร์หลาย ๆ สำหรับสิ่งนี้เราจำเป็นต้องใช้ตัวเลือกการกำหนดค่า multiCapabilities ดังนี้ -
multiCapabilities: [{
'browserName': 'chrome'
},{
'browserName': 'firefox'
}]
Framework ไหน?
กรอบการทดสอบ BDD (Behavior driven development) สองกรอบคือ Jasmine และ Mocha ได้รับการสนับสนุนโดย Protractor เฟรมเวิร์กทั้งสองใช้ JavaScript และ Node.js ไวยากรณ์รายงานและโครงร่างที่จำเป็นสำหรับการเขียนและจัดการการทดสอบมีให้โดยกรอบงานเหล่านี้
ต่อไปเราจะดูว่าเราสามารถติดตั้งเฟรมเวิร์กต่างๆได้อย่างไร -
กรอบดอกมะลิ
เป็นกรอบการทดสอบเริ่มต้นสำหรับไม้โปรแทรกเตอร์ เมื่อคุณติดตั้งไม้โปรแทรกเตอร์คุณจะได้รับรุ่น Jasmine 2.x ด้วย เราไม่จำเป็นต้องติดตั้งแยกต่างหาก
กรอบมอคค่า
Mocha เป็นอีกหนึ่งกรอบการทดสอบ JavaScript ที่ทำงานบน Node.js สำหรับการใช้ Mocha เป็นกรอบการทดสอบของเราเราจำเป็นต้องใช้อินเทอร์เฟซ BDD (Behavior driven development) และการยืนยันของ Chai กับ Chai As Promised การติดตั้งสามารถทำได้โดยใช้คำสั่งต่อไปนี้ -
npm install -g mocha
npm install chai
npm install chai-as-promised
อย่างที่คุณเห็นตัวเลือก -g ถูกใช้ในขณะติดตั้งมอคค่าเนื่องจากเราได้ติดตั้งไม้โปรแทรกเตอร์ทั่วโลกโดยใช้ตัวเลือก -g หลังจากติดตั้งแล้วเราจำเป็นต้องกำหนดและตั้งค่า Chai ภายในไฟล์ทดสอบของเรา สามารถทำได้ดังนี้ -
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
หลังจากนี้เราสามารถใช้ Chai As Promised ได้ -
expect(myElement.getText()).to.eventually.equal('some text');
ตอนนี้เราจำเป็นต้องตั้งค่าคุณสมบัติกรอบเป็น mocha ของไฟล์ config โดยการเพิ่ม framework: 'mocha' คุณสามารถเพิ่มตัวเลือกเช่น 'นักข่าว' และ 'ช้า' สำหรับมอคค่าในไฟล์กำหนดค่าได้ดังนี้ -
mochaOpts: {
reporter: "spec", slow: 3000
}
กรอบแตงกวา
สำหรับการใช้ Cucumber เป็นกรอบการทดสอบของเราเราจำเป็นต้องรวมเข้ากับ Protractor ด้วยตัวเลือกกรอบ custom. การติดตั้งสามารถทำได้โดยใช้คำสั่งต่อไปนี้
npm install -g cucumber
npm install --save-dev protractor-cucumber-framework
อย่างที่คุณเห็นอ็อพชัน -g ถูกใช้ในขณะติดตั้ง Cucumber นั่นเป็นเพราะเราได้ติดตั้ง Protractor ทั่วโลกด้วยตัวเลือก -g ต่อไปเราต้องตั้งค่าคุณสมบัติกรอบเป็นcustom ของไฟล์ config โดยเพิ่ม framework: 'custom' และ frameworkPath: 'Protractor-cucumber-framework' ไปยังไฟล์ config ชื่อ cucumberConf.js
โค้ดตัวอย่างที่แสดงด้านล่างเป็นไฟล์ cucumberConf.js พื้นฐานซึ่งสามารถใช้เพื่อเรียกใช้ไฟล์คุณสมบัติแตงกวาด้วย Protractor -
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
baseUrl: 'https://angularjs.org/',
capabilities: {
browserName:'Firefox'
},
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),
specs: [
'./cucumber/*.feature'
],
// cucumber command line options
cucumberOpts: {
require: ['./cucumber/*.js'],
tags: [],
strict: true,
format: ["pretty"],
'dry-run': false,
compiler: []
},
onPrepare: function () {
browser.manage().window().maximize();
}
};
ในบทนี้ให้เราเข้าใจวิธีเขียนแบบทดสอบแรกใน Protractor
ไฟล์ที่ Protractor ต้องการ
ไม้โปรแทรกเตอร์ต้องการสองไฟล์ต่อไปนี้เพื่อเรียกใช้ -
ข้อมูลจำเพาะหรือไฟล์ทดสอบ
เป็นไฟล์สำคัญอย่างหนึ่งในการเรียกใช้ Protractor ในไฟล์นี้เราจะเขียนโค้ดทดสอบจริงของเรา โค้ดทดสอบเขียนโดยใช้ไวยากรณ์ของกรอบการทดสอบของเรา
ตัวอย่างเช่นถ้าเราใช้ Jasmine จากนั้นโค้ดทดสอบจะถูกเขียนโดยใช้ไวยากรณ์ของ Jasmine. ไฟล์นี้จะมีขั้นตอนการทำงานและการยืนยันทั้งหมดของการทดสอบ
พูดง่ายๆเราสามารถพูดได้ว่าไฟล์นี้มีตรรกะและตัวระบุตำแหน่งเพื่อโต้ตอบกับแอปพลิเคชัน
ตัวอย่าง
ต่อไปนี้เป็นสคริปต์ง่ายๆ TestSpecification.js โดยมีกรณีทดสอบเพื่อนำทางไปยัง URL และตรวจสอบชื่อหน้า -
//TestSpecification.js
describe('Protractor Demo', function() {
it('to check the page title', function() {
browser.ignoreSynchronization = true;
browser.get('https://www.tutorialspoint.com/tutorialslibrary.htm');
browser.driver.getTitle().then(function(pageTitle) {
expect(pageTitle).toEqual('Free Online Tutorials and Courses');
});
});
});
คำอธิบายรหัส
รหัสของไฟล์ข้อมูลจำเพาะข้างต้นสามารถอธิบายได้ดังนี้ -
เบราว์เซอร์
เป็นตัวแปรส่วนกลางที่สร้างโดย Protractor เพื่อจัดการคำสั่งระดับเบราว์เซอร์ทั้งหมด มันเป็นกระดาษห่อหุ้มรอบ ๆ อินสแตนซ์ของ WebDriver browser.get () เป็นวิธี Selenium ง่ายๆที่จะบอกให้ Protractor โหลดหน้าใดหน้าหนึ่ง
describe และ it- ทั้งสองเป็นไวยากรณ์ของกรอบการทดสอบจัสมิน ’Describe’ ใช้เพื่อบรรจุขั้นตอนสุดท้ายถึงจุดสิ้นสุดของกรณีทดสอบของเราในขณะที่ ‘it’มีสถานการณ์ทดสอบบางส่วน เราสามารถมีหลาย‘it’ บล็อกในโปรแกรมกรณีทดสอบของเรา
Expect - เป็นการยืนยันที่เรากำลังเปรียบเทียบชื่อหน้าเว็บกับข้อมูลที่กำหนดไว้ล่วงหน้า
ignoreSynchronization- เป็นแท็กของเบราว์เซอร์ที่ใช้เมื่อเราจะพยายามทดสอบเว็บไซต์ที่ไม่ใช่เชิงมุม ไม้โปรแทรกเตอร์คาดว่าจะทำงานกับเว็บไซต์เชิงมุมเท่านั้น แต่ถ้าเราต้องการทำงานกับเว็บไซต์ที่ไม่ใช่เชิงมุมต้องตั้งค่าแท็กนี้เป็น“true”.
ไฟล์กำหนดค่า
ตามชื่อที่แนะนำไฟล์นี้จะให้คำอธิบายสำหรับตัวเลือกการกำหนดค่าไม้โปรแทรกเตอร์ทั้งหมด โดยทั่วไปจะบอก Protractor ดังต่อไปนี้ -
- จะหาไฟล์ทดสอบหรือข้อมูลจำเพาะได้ที่ไหน
- เลือกเบราว์เซอร์ใด
- กรอบการทดสอบใดที่จะใช้
- จะคุยกับเซิร์ฟเวอร์ Selenium ได้ที่ไหน
ตัวอย่าง
ต่อไปนี้เป็นสคริปต์ธรรมดา config.js ที่มีการทดสอบ
// config.js
exports.config = {
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['TestSpecification.js'],
คำอธิบายรหัส
โค้ดของไฟล์กำหนดค่าด้านบนที่มีพารามิเตอร์พื้นฐานสามตัวสามารถอธิบายได้ดังนี้ -
พารามิเตอร์ความสามารถ
พารามิเตอร์นี้ใช้เพื่อระบุชื่อของเบราว์เซอร์ สามารถเห็นได้ในบล็อกโค้ดต่อไปนี้ของไฟล์ conf.js -
exports.config = {
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
ดังที่เห็นข้างต้นชื่อของเบราว์เซอร์ที่ระบุที่นี่คือ 'chrome' ซึ่งเป็นเบราว์เซอร์เริ่มต้นสำหรับ Protractor เรายังสามารถเปลี่ยนชื่อของบราวเซอร์
พารามิเตอร์กรอบ
พารามิเตอร์นี้ใช้เพื่อระบุชื่อของกรอบการทดสอบ สามารถเห็นได้ในบล็อกโค้ดต่อไปนี้ของไฟล์ config.js -
exports.config = {
directConnect: true,
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
เรากำลังใช้กรอบการทดสอบ 'ดอกมะลิ'
พารามิเตอร์การประกาศไฟล์ต้นฉบับ
พารามิเตอร์นี้ใช้เพื่อระบุชื่อของการประกาศไฟล์ต้นทาง สามารถเห็นได้ในบล็อกโค้ดต่อไปนี้ของไฟล์ conf.js -
exports.config = {
directConnect: true,
// Spec patterns are relative to the current working
directory when protractor is called.
specs: ['TsetSpecification.js'],
ดังที่เห็นด้านบนชื่อของการประกาศไฟล์ต้นฉบับที่ให้ไว้ที่นี่คือ ‘TestSpecification.js’. เป็นเพราะตัวอย่างนี้เราได้สร้างไฟล์ข้อมูลจำเพาะด้วยชื่อTestSpecification.js.
ดำเนินการรหัส
เนื่องจากเรามีความเข้าใจพื้นฐานเกี่ยวกับไฟล์ที่จำเป็นและการเข้ารหัสสำหรับการเรียกใช้ Protractor แล้วให้เราลองเรียกใช้ตัวอย่าง เราสามารถทำตามขั้นตอนต่อไปนี้เพื่อดำเนินการตามตัวอย่างนี้ -
Step 1 - ขั้นแรกให้เปิดพรอมต์คำสั่ง
Step 2 - ต่อไปเราต้องไปที่ไดเร็กทอรีที่เราบันทึกไฟล์ของเราคือ config.js และ TestSpecification.js.
Step 3 - ตอนนี้เรียกใช้ไฟล์ config.js โดยรันคำสั่ง Protrcator config.js
ภาพหน้าจอที่แสดงด้านล่างจะอธิบายขั้นตอนข้างต้นสำหรับการดำเนินการตามตัวอย่าง -
เห็นในภาพหน้าจอว่าผ่านการทดสอบแล้ว
ตอนนี้สมมติว่าเรากำลังทดสอบเว็บไซต์ที่ไม่ใช่เชิงมุมและไม่ได้วางแท็กเพิกเฉยต่อการซิงโครไนซ์เป็นจริงหลังจากเรียกใช้โค้ดแล้วเราจะได้รับข้อผิดพลาด "ไม่พบเชิงมุมบนหน้า"
สามารถเห็นได้จากภาพหน้าจอต่อไปนี้ -
การสร้างรายงาน
จนถึงตอนนี้เราได้พูดคุยเกี่ยวกับไฟล์ที่จำเป็นและการเข้ารหัสสำหรับการเรียกใช้กรณีทดสอบ ไม้โปรแทรกเตอร์ยังสามารถสร้างรายงานสำหรับกรณีทดสอบ เพื่อการนี้สนับสนุนจัสมิน สามารถใช้ JunitXMLReporter เพื่อสร้างรายงานการดำเนินการทดสอบโดยอัตโนมัติ
แต่ก่อนหน้านั้นเราต้องติดตั้งจัสมินนักข่าวด้วยความช่วยเหลือของคำสั่งต่อไปนี้ -
npm install -g jasmine-reporters
อย่างที่คุณเห็นตัวเลือก -g ถูกใช้ในขณะติดตั้ง Jasmine Reporters นั่นเป็นเพราะเราได้ติดตั้ง Protractor ทั่วโลกด้วยตัวเลือก -g
หลังจากติดตั้งจัสมินผู้สื่อข่าวสำเร็จเราต้องเพิ่มรหัสต่อไปนี้ลงในไฟล์ config.js ที่ใช้ก่อนหน้านี้ -
onPrepare: function(){ //configure junit xml report
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
filePrefix: 'guitest-xmloutput',
savePath: 'test/reports'
}));
ตอนนี้ไฟล์ config.js ใหม่ของเราจะเป็นดังนี้ -
// An example configuration file.
exports.config = {
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['TestSpecification.js'],
//framework: "jasmine2", //must set it if you use JUnitXmlReporter
onPrepare: function(){ //configure junit xml report
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
filePrefix: 'guitest-xmloutput',
savePath: 'reports'
}));
},
};
หลังจากเรียกใช้ไฟล์ config ข้างต้นในลักษณะเดียวกันเราได้เรียกใช้ก่อนหน้านี้มันจะสร้างไฟล์ XML ที่มีรายงานภายใต้ไดเร็กทอรีรากใน reportsโฟลเดอร์ หากการทดสอบประสบความสำเร็จรายงานจะมีลักษณะดังนี้ -
แต่หากการทดสอบล้มเหลวรายงานจะมีลักษณะดังที่แสดงด้านล่าง -
ไม้โปรแทรกเตอร์ - APIS หลัก
บทนี้ช่วยให้คุณเข้าใจ API หลักต่างๆที่เป็นกุญแจสำคัญในการทำงานของไม้โปรแทรกเตอร์
ความสำคัญของ Protractor API
Protractor มี API ที่หลากหลายซึ่งมีความสำคัญมากในการดำเนินการต่อไปนี้เพื่อรับสถานะปัจจุบันของเว็บไซต์ -
- รับองค์ประกอบ DOM ของหน้าเว็บที่เรากำลังจะทดสอบ
- การโต้ตอบกับองค์ประกอบ DOM
- กำหนดการดำเนินการให้กับพวกเขา
- แบ่งปันข้อมูลให้กับพวกเขา
ในการทำงานข้างต้นสิ่งสำคัญคือต้องทำความเข้าใจ Protractor API
Protractor API ต่างๆ
อย่างที่เราทราบกันดีว่า Protractor เป็นเครื่องห่อหุ้มรอบ Selenium-WebDriver ซึ่งเป็นการผูก WebDriver สำหรับ Node.js Protractor มี API ดังต่อไปนี้ -
เบราว์เซอร์
เป็นกระดาษห่อหุ้มรอบอินสแตนซ์ของ WebDriver ซึ่งใช้เพื่อจัดการกับคำสั่งระดับเบราว์เซอร์เช่นการนำทางข้อมูลทั่วทั้งหน้าเป็นต้นตัวอย่างเช่นวิธี browser.get จะโหลดหน้า
ธาตุ
ใช้เพื่อค้นหาและโต้ตอบกับองค์ประกอบ DOM บนหน้าที่เรากำลังทดสอบ เพื่อจุดประสงค์นี้จำเป็นต้องมีพารามิเตอร์เดียวเพื่อค้นหาองค์ประกอบ
ตัวระบุตำแหน่ง (โดย)
มันคือชุดของกลยุทธ์การระบุตำแหน่งองค์ประกอบ ตัวอย่างเช่นองค์ประกอบสามารถพบได้โดยตัวเลือก CSS ตาม ID หรือแอตทริบิวต์อื่น ๆ ที่เชื่อมโยงกับ ng-model
ต่อไปเราจะพูดถึงรายละเอียดเกี่ยวกับ API เหล่านี้และฟังก์ชันต่างๆ
เบราว์เซอร์ API
ดังที่ได้กล่าวไว้ข้างต้นมันเป็นเครื่องห่อหุ้มรอบ ๆ อินสแตนซ์ของ WebDriver สำหรับจัดการคำสั่งระดับเบราว์เซอร์ ทำหน้าที่ต่างๆดังนี้ -
ฟังก์ชั่นและคำอธิบาย
ฟังก์ชันของ ProtractorBrowser API มีดังต่อไปนี้
browser.angularAppRoot
ฟังก์ชันของ Browser API นี้จะตั้งค่าตัวเลือก CSS สำหรับองค์ประกอบที่เราจะหา Angular โดยปกติแล้วฟังก์ชันนี้จะอยู่ใน "body" แต่ในกรณีที่ ng-app ของเราจะอยู่ในส่วนย่อยของหน้า มันอาจเป็นองค์ประกอบย่อยด้วย
browser.waitForAngularEnabled
ฟังก์ชันของ Browser API นี้สามารถตั้งค่าเป็นจริงหรือเท็จได้ ตามชื่อที่แนะนำถ้าฟังก์ชันนี้ถูกตั้งค่าเป็นเท็จไม้โปรแทรกเตอร์จะไม่รอ Angular$http and $หมดเวลาทำงานให้เสร็จสิ้นก่อนที่จะโต้ตอบกับเบราว์เซอร์ นอกจากนี้เรายังสามารถอ่านสถานะปัจจุบันได้โดยไม่ต้องเปลี่ยนแปลงโดยเรียก waitForAngularEnabled () โดยไม่ต้องส่งค่า
browser.getProcessedConfig
ด้วยความช่วยเหลือของฟังก์ชัน API ของเบราว์เซอร์นี้เราจะได้รับวัตถุการกำหนดค่าที่ประมวลผลรวมถึงข้อกำหนดและความสามารถที่กำลังทำงานอยู่
browser.forkNewDriverInstance
ตามชื่อที่แนะนำฟังก์ชันนี้จะแยกอินสแตนซ์ของเบราว์เซอร์อื่นเพื่อใช้ในการทดสอบเชิงโต้ตอบ สามารถเรียกใช้โดยเปิดใช้งานและปิดใช้โฟลว์การควบคุม ตัวอย่างแสดงไว้ด้านล่างสำหรับทั้งสองกรณี -
Example 1
วิ่ง browser.forkNewDriverInstance() ด้วยการควบคุมโฟลว์ที่เปิดใช้งาน -
var fork = browser.forkNewDriverInstance();
fork.get(‘page1’);
Example 2
วิ่ง browser.forkNewDriverInstance() เมื่อปิดการใช้งานโฟลว์การควบคุม -
var fork = await browser.forkNewDriverInstance().ready;
await forked.get(‘page1’);
browser.restart
ตามชื่อที่แนะนำมันจะรีสตาร์ทเบราว์เซอร์โดยปิดอินสแตนซ์ของเบราว์เซอร์และสร้างใหม่ นอกจากนี้ยังสามารถทำงานโดยเปิดและปิดใช้โฟลว์การควบคุม ตัวอย่างแสดงไว้ด้านล่างสำหรับทั้งสองกรณี -
Example 1 - วิ่ง browser.restart() ด้วยการควบคุมโฟลว์ที่เปิดใช้งาน -
browser.get(‘page1’);
browser.restart();
browser.get(‘page2’);
Example 2 - วิ่ง browser.forkNewDriverInstance() เมื่อปิดการใช้งานโฟลว์การควบคุม -
await browser.get(‘page1’);
await browser.restart();
await browser.get(‘page2’);
browser.restartSync
มันคล้ายกับฟังก์ชัน browser.restart () ข้อแตกต่างเพียงอย่างเดียวคือส่งคืนอินสแตนซ์เบราว์เซอร์ใหม่โดยตรงแทนที่จะส่งคืนสัญญาที่แก้ไขกับอินสแตนซ์เบราว์เซอร์ใหม่ สามารถทำงานได้เมื่อเปิดใช้งานโฟลว์การควบคุมเท่านั้น
Example - วิ่ง browser.restartSync() ด้วยการควบคุมโฟลว์ที่เปิดใช้งาน -
browser.get(‘page1’);
browser.restartSync();
browser.get(‘page2’);
browser.useAllAngular2AppRoots
ตามชื่อมันเข้ากันได้กับ Angular2 เท่านั้น มันจะค้นหาแอพเชิงมุมทั้งหมดที่มีอยู่ในเพจในขณะที่ค้นหาองค์ประกอบหรือรอความเสถียร
browser.waitForAngular
ฟังก์ชัน API ของเบราว์เซอร์นี้สั่งให้ WebDriver รอจนกว่า Angular จะแสดงผลเสร็จสิ้นและไม่มีการค้าง $http or $หมดเวลาโทรก่อนดำเนินการต่อ
browser.findElement
ตามชื่อที่แนะนำฟังก์ชัน API ของเบราว์เซอร์นี้รอให้ Angular แสดงผลเสร็จสิ้นก่อนที่จะค้นหาองค์ประกอบ
browser.isElementPresent
ตามชื่อที่แนะนำฟังก์ชัน API ของเบราว์เซอร์นี้จะทดสอบเพื่อหาองค์ประกอบที่จะแสดงบนหน้าเว็บหรือไม่
browser.addMockModule
มันจะเพิ่มโมดูลที่จะโหลดก่อน Angular ทุกครั้งที่เรียกเมธอด Protractor.get
Example
browser.addMockModule('modName', function() {
angular.module('modName', []).value('foo', 'bar');
});
browser.clearMockModules
ไม่เหมือน browser.addMockModule มันจะล้างรายการโมดูลจำลองที่ลงทะเบียนไว้
browser.removeMockModule
ตามชื่อที่แนะนำมันจะลบโมดูลจำลองการลงทะเบียน ตัวอย่าง: browser.removeMockModule ('modName');
browser.getRegisteredMockModules
ตรงข้ามกับ browser.clearMockModule จะได้รับรายชื่อโมดูลจำลองที่ลงทะเบียน
browser.get
เราสามารถใช้ browser.get () เพื่อนำทางเบราว์เซอร์ไปยังเว็บแอดเดรสเฉพาะและโหลดโมดูลจำลองสำหรับเพจนั้นก่อนโหลด Angular
Example
browser.get(url);
browser.get('http://localhost:3000');
// This will navigate to the localhost:3000 and will load mock module if needed
browser.refresh
ตามชื่อที่แนะนำการดำเนินการนี้จะโหลดหน้าปัจจุบันซ้ำและโหลดโมดูลจำลองก่อน Angular
browser.navigate
ตามชื่อที่แนะนำมันถูกใช้เพื่อผสมวิธีการนำทางกลับเข้าไปในวัตถุการนำทางเพื่อให้เรียกใช้เหมือนเดิม ตัวอย่าง: driver.navigate (). refresh ()
browser.setLocation
ใช้เพื่อเรียกดูหน้าอื่นโดยใช้การนำทางในหน้า
Example
browser.get('url/ABC');
browser.setLocation('DEF');
expect(browser.getCurrentUrl())
.toBe('url/DEF');
มันจะนำทางจากหน้า ABC ไปยัง DEF
browser.debugger
ตามชื่อที่แนะนำต้องใช้กับการดีบักไม้โปรแทรกเตอร์ โดยพื้นฐานแล้วฟังก์ชันนี้จะเพิ่มงานให้กับโฟลว์การควบคุมเพื่อหยุดการทดสอบชั่วคราวและฉีดฟังก์ชันตัวช่วยลงในเบราว์เซอร์เพื่อให้การดีบักสามารถทำได้ในคอนโซลเบราว์เซอร์
browser.pause
ใช้สำหรับการดีบักการทดสอบ WebDriver เราสามารถใช้browser.pause() ในการทดสอบของเราเพื่อป้อนดีบักเกอร์ไม้โปรแทรกเตอร์จากจุดนั้นในโฟลว์ควบคุม
Example
element(by.id('foo')).click();
browser.pause();
// Execution will stop before the next click action.
element(by.id('bar')).click();
browser.controlFlowEnabled
ใช้เพื่อกำหนดว่าโฟลว์ควบคุมถูกเปิดใช้งานหรือไม่
ไม้โปรแทรกเตอร์ - APIS หลัก (CONTD ... )
ในบทนี้ให้เราเรียนรู้เพิ่มเติมเกี่ยวกับ API หลักของ Protractor
Elements API
องค์ประกอบเป็นหนึ่งในฟังก์ชันระดับโลกที่เปิดเผยโดยไม้โปรแทรกเตอร์ ฟังก์ชันนี้ใช้ตัวระบุตำแหน่งและส่งกลับค่าต่อไปนี้ -
- ElementFinder ที่ค้นหาองค์ประกอบเดียวตามตัวระบุตำแหน่ง
- ElementArrayFinder ที่ค้นหาอาร์เรย์ขององค์ประกอบตามตัวระบุตำแหน่ง
ทั้งสองวิธีข้างต้นสนับสนุนการผูกมัดดังที่กล่าวไว้ด้านล่าง
ฟังก์ชัน Chaining ของ ElementArrayFinder และคำอธิบาย
ต่อไปนี้เป็นหน้าที่ของ ElementArrayFinder -
element.all(locator).clone
ตามชื่อที่แนะนำฟังก์ชันนี้จะสร้างสำเนาตื้นของอาร์เรย์ขององค์ประกอบเช่น ElementArrayFinder
element.all(locator).all(locator)
โดยทั่วไปฟังก์ชันนี้จะส่งคืน ElementArrayFinder ใหม่ซึ่งอาจว่างเปล่าหรือมีองค์ประกอบลูก สามารถใช้สำหรับการเลือกหลายองค์ประกอบเป็นอาร์เรย์ดังนี้
Example
element.all(locator).all(locator)
elementArr.all(by.css(‘.childselector’));
// it will return another ElementFindArray as child element based on child locator.
element.all(locator).filter(filterFn)
ตามชื่อที่แนะนำหลังจากใช้ฟังก์ชันตัวกรองกับแต่ละองค์ประกอบภายใน ElementArrayFinder มันจะส่งคืน ElementArrayFinder ใหม่พร้อมกับองค์ประกอบทั้งหมดที่ผ่านฟังก์ชันตัวกรอง โดยทั่วไปมีสองอาร์กิวเมนต์แรกคือ ElementFinder และที่สองคือดัชนี นอกจากนี้ยังสามารถใช้ในวัตถุหน้า
Example
View
<ul class = "items">
<li class = "one">First</li>
<li class = "two">Second</li>
<li class = "three">Third</li>
</ul>
Code
element.all(by.css('.items li')).filter(function(elem, index) {
return elem.getText().then(function(text) {
return text === 'Third';
});
}).first().click();
element.all(locator).get(index)
ด้วยความช่วยเหลือนี้เราจะได้รับองค์ประกอบภายใน ElementArrayFinder โดยดัชนี โปรดทราบว่าดัชนีเริ่มต้นที่ 0 และดัชนีเชิงลบถูกรวมเข้าด้วยกัน
Example
View
<ul class = "items">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
Code
let list = element.all(by.css('.items li'));
expect(list.get(0).getText()).toBe('First');
expect(list.get(1).getText()).toBe('Second');
element.all(locator).first()
ตามชื่อที่แนะนำสิ่งนี้จะได้รับองค์ประกอบแรกสำหรับ ElementArrayFinder มันจะไม่ดึงองค์ประกอบพื้นฐาน
Example
View
<ul class = "items">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
Code
let first = element.all(by.css('.items li')).first();
expect(first.getText()).toBe('First');
element.all(locator).last()
ตามชื่อแนะนำสิ่งนี้จะได้รับองค์ประกอบสุดท้ายสำหรับ ElementArrayFinder มันจะไม่ดึงองค์ประกอบพื้นฐาน
Example
View
<ul class = "items">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
Code
let first = element.all(by.css('.items li')).last();
expect(last.getText()).toBe('Third');
element.all(locator).all(selector)
ใช้เพื่อค้นหาอาร์เรย์ขององค์ประกอบภายในพาเรนต์เมื่อการเรียกไปยัง $$ อาจถูกล่ามโซ่
Example
View
<div class = "parent">
<ul>
<li class = "one">First</li>
<li class = "two">Second</li>
<li class = "three">Third</li>
</ul>
</div>
Code
let items = element(by.css('.parent')).$$('li');
element.all(locator).count()
ตามชื่อที่แนะนำจะนับจำนวนองค์ประกอบที่แสดงโดย ElementArrayFinder มันจะไม่ดึงองค์ประกอบพื้นฐาน
Example
View
<ul class = "items">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
Code
let list = element.all(by.css('.items li'));
expect(list.count()).toBe(3);
element.all(locator).isPresent()
มันจะจับคู่องค์ประกอบกับตัวค้นหา มันสามารถคืนค่าจริงหรือเท็จ จริงหากมีองค์ประกอบใด ๆ ที่ตรงกับตัวค้นหาและ False เป็นอย่างอื่น
Example
expect($('.item').isPresent()).toBeTruthy();
element.all(locator).locator
ตามชื่อที่แนะนำมันจะส่งคืนตัวระบุตำแหน่งที่เกี่ยวข้องมากที่สุด
Example
$('#ID1').locator();
// returns by.css('#ID1')
$('#ID1').$('#ID2').locator();
// returns by.css('#ID2')
$$('#ID1').filter(filterFn).get(0).click().locator();
// returns by.css('#ID1')
element.all(locator).then(thenFunction)
มันจะดึงองค์ประกอบที่แสดงโดย ElementArrayFinder
Example
View
<ul class = "items">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
Code
element.all(by.css('.items li')).then(function(arr) {
expect(arr.length).toEqual(3);
});
element.all(locator).each(eachFunction)
ตามชื่อที่แนะนำมันจะเรียกใช้ฟังก์ชันอินพุตใน ElementFinder แต่ละตัวที่แสดงโดย ElementArrayFinder
Example
View
<ul class = "items">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
Code
element.all(by.css('.items li')).each(function(element, index) {
// It will print First 0, Second 1 and Third 2.
element.getText().then(function (text) {
console.log(index, text);
});
});
element.all(locator).map(mapFunction)
ตามชื่อแนะนำมันจะใช้ฟังก์ชันแผนที่กับแต่ละองค์ประกอบภายใน ElementArrayFinder มันมีสองข้อโต้แย้ง อันดับแรกจะเป็น ElementFinder และอันดับที่สองคือดัชนี
Example
View
<ul class = "items">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
Code
let items = element.all(by.css('.items li')).map(function(elm, index) {
return {
index: index,
text: elm.getText(),
class: elm.getAttribute('class')
};
});
expect(items).toEqual([
{index: 0, text: 'First', class: 'one'},
{index: 1, text: 'Second', class: 'two'},
{index: 2, text: 'Third', class: 'three'}
]);
element.all(locator).reduce(reduceFn)
ตามชื่อที่แนะนำมันจะใช้ฟังก์ชันลดกับตัวสะสมและทุกองค์ประกอบที่พบโดยใช้ตัวระบุตำแหน่ง ฟังก์ชันนี้จะลดทุกองค์ประกอบให้เป็นค่าเดียว
Example
View
<ul class = "items">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
Code
let value = element.all(by.css('.items li')).reduce(function(acc, elem) {
return elem.getText().then(function(text) {
return acc + text + ' ';
});
}, '');
expect(value).toEqual('First Second Third ');
element.all(locator).evaluate
ตามชื่อที่แนะนำมันจะประเมินอินพุตว่าอยู่ในขอบเขตขององค์ประกอบพื้นฐานปัจจุบันหรือไม่
Example
View
<span class = "foo">{{letiableInScope}}</span>
Code
let value =
element.all(by.css('.foo')).evaluate('letiableInScope');
element.all(locator).allowAnimations
ตามการแนะนำชื่อจะเป็นตัวกำหนดว่าอนุญาตให้ใช้ภาพเคลื่อนไหวในองค์ประกอบพื้นฐานปัจจุบันได้หรือไม่
Example
element(by.css('body')).allowAnimations(false);
ฟังก์ชั่นการเชื่อมโยงของ ElementFinder และคำอธิบาย
ฟังก์ชั่นการเชื่อมโยงของ ElementFinder และคำอธิบาย -
element(locator).clone
ตามชื่อที่แนะนำฟังก์ชันนี้จะสร้างสำเนาแบบตื้นของ ElementFinder
element(locator).getWebElement()
มันจะส่งคืน WebElement ที่แสดงโดย ElementFinder นี้และข้อผิดพลาด WebDriver จะถูกโยนทิ้งหากองค์ประกอบนั้นไม่มีอยู่
Example
View
<div class="parent">
some text
</div>
Code
// All the four following expressions are equivalent.
$('.parent').getWebElement();
element(by.css('.parent')).getWebElement();
browser.driver.findElement(by.css('.parent'));
browser.findElement(by.css('.parent'));
element(locator).all(locator)
จะพบอาร์เรย์ขององค์ประกอบภายในพาเรนต์
Example
View
<div class = "parent">
<ul>
<li class = "one">First</li>
<li class = "two">Second</li>
<li class = "three">Third</li>
</ul>
</div>
Code
let items = element(by.css('.parent')).all(by.tagName('li'));
element(locator).element(locator)
จะพบองค์ประกอบภายในผู้ปกครอง
Example
View
<div class = "parent">
<div class = "child">
Child text
<div>{{person.phone}}</div>
</div>
</div>
Code
// Calls Chain 2 element.
let child = element(by.css('.parent')).
element(by.css('.child'));
expect(child.getText()).toBe('Child text\n981-000-568');
// Calls Chain 3 element.
let triple = element(by.css('.parent')).
element(by.css('.child')).
element(by.binding('person.phone'));
expect(triple.getText()).toBe('981-000-568');
element(locator).all(selector)
จะพบอาร์เรย์ขององค์ประกอบภายในพาเรนต์เมื่อการโทรไปยัง $$ อาจถูกล่ามโซ่
Example
View
<div class = "parent">
<ul>
<li class = "one">First</li>
<li class = "two">Second</li>
<li class = "three">Third</li>
</ul>
</div>
Code
let items = element(by.css('.parent')).$$('li'));
element(locator).$(locator)
จะพบองค์ประกอบภายในผู้ปกครองเมื่อการโทรไปยัง $ อาจถูกล่ามโซ่
Example
View
<div class = "parent">
<div class = "child">
Child text
<div>{{person.phone}}</div>
</div>
</div>
Code
// Calls Chain 2 element.
let child = element(by.css('.parent')).
$('.child')); expect(child.getText()).toBe('Child text\n981-000-568'); // Calls Chain 3 element. let triple = element(by.css('.parent')). $('.child')).
element(by.binding('person.phone'));
expect(triple.getText()).toBe('981-000-568');
element(locator).isPresent()
มันจะกำหนดว่าองค์ประกอบถูกนำเสนอในหน้าหรือไม่
Example
View
<span>{{person.name}}</span>
Code
expect(element(by.binding('person.name')).isPresent()).toBe(true);
// will check for the existence of element
expect(element(by.binding('notPresent')).isPresent()).toBe(false);
// will check for the non-existence of element
element(locator).isElementPresent()
มันเหมือนกับ element (locator) .isPresent () ข้อแตกต่างเพียงอย่างเดียวคือจะตรวจสอบว่าองค์ประกอบที่ระบุโดย sublocator มีอยู่หรือไม่แทนที่จะเป็นตัวค้นหาองค์ประกอบปัจจุบัน
element.all(locator).evaluate
ตามชื่อที่แนะนำมันจะประเมินอินพุตว่าอยู่ในขอบเขตขององค์ประกอบพื้นฐานปัจจุบันหรือไม่
Example
View
<span id = "foo">{{letiableInScope}}</span>
Code
let value = element(by.id('.foo')).evaluate('letiableInScope');
element(locator).allowAnimations
ตามชื่อที่แนะนำจะเป็นตัวกำหนดว่าอนุญาตให้ใช้ภาพเคลื่อนไหวในองค์ประกอบพื้นฐานปัจจุบันหรือไม่
Example
element(by.css('body')).allowAnimations(false);
element(locator).equals
ตามชื่อมันจะเปรียบเทียบองค์ประกอบเพื่อความเท่าเทียมกัน
ตัวระบุตำแหน่ง (โดย) API
โดยพื้นฐานแล้วเป็นชุดของกลยุทธ์การระบุตำแหน่งองค์ประกอบที่ให้วิธีการค้นหาองค์ประกอบในแอปพลิเคชันเชิงมุมโดยการผูกโมเดลเป็นต้น
Functions and their descriptions
ฟังก์ชันของ ProtractorLocators API มีดังนี้ -
by.addLocator(locatorName,fuctionOrScript)
มันจะเพิ่มตัวระบุตำแหน่งให้กับอินสแตนซ์ของ ProtrcatorBy ซึ่งสามารถใช้กับองค์ประกอบเพิ่มเติมได้ (by.locatorName (args))
Example
View
<button ng-click = "doAddition()">Go!</button>
Code
// Adding the custom locator.
by.addLocator('buttonTextSimple',
function(buttonText, opt_parentElement, opt_rootSelector) {
var using = opt_parentElement || document,
buttons = using.querySelectorAll('button');
return Array.prototype.filter.call(buttons, function(button) {
return button.textContent === buttonText;
});
});
element(by.buttonTextSimple('Go!')).click();// Using the custom locator.
by.binding
ตามชื่อจะพบองค์ประกอบโดยการผูกข้อความ จะมีการจับคู่บางส่วนเพื่อให้องค์ประกอบใด ๆ ที่ผูกไว้กับตัวแปรที่มีสตริงอินพุตจะถูกส่งกลับ
Example
View
<span>{{person.name}}</span>
<span ng-bind = "person.email"></span>
Code
var span1 = element(by.binding('person.name'));
expect(span1.getText()).toBe('Foo');
var span2 = element(by.binding('person.email'));
expect(span2.getText()).toBe('[email protected]');
by.exactbinding
ตามชื่อที่แนะนำจะพบองค์ประกอบโดยการผูกที่แน่นอน
Example
View
<spangt;{{ person.name }}</spangt;
<span ng-bind = "person-email"gt;</spangt;
<spangt;{{person_phone|uppercase}}</span>
Code
expect(element(by.exactBinding('person.name')).isPresent()).toBe(true);
expect(element(by.exactBinding('person-email')).isPresent()).toBe(true);
expect(element(by.exactBinding('person')).isPresent()).toBe(false);
expect(element(by.exactBinding('person_phone')).isPresent()).toBe(true);
expect(element(by.exactBinding('person_phone|uppercase')).isPresent()).toBe(true);
expect(element(by.exactBinding('phone')).isPresent()).toBe(false);
by.model(modelName)
ตามชื่อที่แนะนำมันจะค้นหาองค์ประกอบโดยนิพจน์ ng-model
Example
View
<input type = "text" ng-model = "person.name">
Code
var input = element(by.model('person.name'));
input.sendKeys('123');
expect(input.getAttribute('value')).toBe('Foo123');
by.buttonText
ตามชื่อจะพบปุ่มตามข้อความ
Example
View
<button>Save</button>
Code
element(by.buttonText('Save'));
by.partialButtonText
ตามชื่อจะพบปุ่มตามข้อความบางส่วน
Example
View
<button>Save my file</button>
Code
element(by.partialButtonText('Save'));
by.repeater
ตามชื่อมันจะพบองค์ประกอบใน ng-repeat
Example
View
<div ng-repeat = "cat in pets">
<span>{{cat.name}}</span>
<span>{{cat.age}}</span>
<</div>
<div class = "book-img" ng-repeat-start="book in library">
<span>{{$index}}</span>
</div>
<div class = "book-info" ng-repeat-end>
<h4>{{book.name}}</h4>
<p>{{book.blurb}}</p>
</div>
Code
var secondCat = element(by.repeater('cat in
pets').row(1)); // It will return the DIV for the second cat.
var firstCatName = element(by.repeater('cat in pets').
row(0).column('cat.name')); // It will return the SPAN for the first cat's name.
by.exactRepeater
ตามชื่อมันจะหาองค์ประกอบโดยทวนที่แน่นอน
Example
View
<li ng-repeat = "person in peopleWithRedHair"></li>
<li ng-repeat = "car in cars | orderBy:year"></li>
Code
expect(element(by.exactRepeater('person in
peopleWithRedHair')).isPresent())
.toBe(true);
expect(element(by.exactRepeater('person in
people')).isPresent()).toBe(false);
expect(element(by.exactRepeater('car in cars')).isPresent()).toBe(true);
by.cssContainingText
ตามชื่อแนะนำมันจะค้นหาองค์ประกอบที่มีสตริงที่แน่นอนโดย CSS
Example
View
<ul>
<li class = "pet">Dog</li>
<li class = "pet">Cat</li>
</ul>
Code
var dog = element(by.cssContainingText('.pet', 'Dog'));
// It will return the li for the dog, but not for the cat.
by.options(optionsDescriptor)
ตามชื่อที่แนะนำมันจะค้นหาองค์ประกอบด้วยนิพจน์ ng-options
Example
View
<select ng-model = "color" ng-options = "c for c in colors">
<option value = "0" selected = "selected">red</option>
<option value = "1">green</option>
</select>
Code
var allOptions = element.all(by.options('c for c in colors'));
expect(allOptions.count()).toEqual(2);
var firstOption = allOptions.first();
expect(firstOption.getText()).toEqual('red');
by.deepCSS(selector)
ตามชื่อแนะนำจะพบองค์ประกอบโดยตัวเลือก CSS ภายใน Shadow DOM
Example
View
<div>
<span id = "outerspan">
<"shadow tree">
<span id = "span1"></span>
<"shadow tree">
<span id = "span2"></span>
</>
</>
</div>
Code
var spans = element.all(by.deepCss('span'));
expect(spans.count()).toEqual(3);
ไม้โปรแทรกเตอร์ - วัตถุ
บทนี้จะกล่าวถึงรายละเอียดเกี่ยวกับวัตถุในไม้โปรแทรกเตอร์
Page Objects คืออะไร?
เพจออบเจ็กต์เป็นรูปแบบการออกแบบที่ได้รับความนิยมในการเขียนการทดสอบ e2e เพื่อเพิ่มประสิทธิภาพการบำรุงรักษาการทดสอบและลดการซ้ำซ้อนของโค้ด อาจถูกกำหนดให้เป็นคลาสเชิงวัตถุที่ทำหน้าที่เป็นอินเทอร์เฟซไปยังหน้า AUT ของคุณ (แอปพลิเคชันที่อยู่ระหว่างการทดสอบ) แต่ก่อนที่จะเจาะลึกลงไปในออบเจ็กต์เพจเราต้องเข้าใจความท้าทายด้วยการทดสอบ UI อัตโนมัติและวิธีจัดการกับสิ่งเหล่านี้
ความท้าทายกับการทดสอบ UI อัตโนมัติ
สิ่งต่อไปนี้เป็นความท้าทายทั่วไปบางประการกับการทดสอบ UI อัตโนมัติ -
การเปลี่ยนแปลง UI
ปัญหาที่พบบ่อยมากขณะทำงานกับการทดสอบ UI คือการเปลี่ยนแปลงที่เกิดขึ้นใน UI ตัวอย่างเช่นเกิดขึ้นเกือบตลอดเวลาที่ปุ่มหรือกล่องข้อความ ฯลฯ มักจะมีการเปลี่ยนแปลงและสร้างปัญหาสำหรับการทดสอบ UI
ขาดการสนับสนุน DSL (ภาษาเฉพาะโดเมน)
อีกปัญหาหนึ่งในการทดสอบ UI คือการขาดการสนับสนุน DSL ด้วยปัญหานี้ทำให้ยากที่จะเข้าใจว่ากำลังทดสอบอะไรอยู่
การทำซ้ำ / การทำซ้ำรหัสจำนวนมาก
ปัญหาที่พบบ่อยถัดไปในการทดสอบ UI คือมีการทำซ้ำหรือโค้ดซ้ำกันมาก สามารถเข้าใจได้ด้วยความช่วยเหลือของโค้ดบรรทัดต่อไปนี้ -
element(by.model(‘event.name’)).sendKeys(‘An Event’);
element(by.model(‘event.name’)).sendKeys(‘Module 3’);
element(by.model(‘event.name’));
การบำรุงรักษาที่ยากลำบาก
เนื่องจากความท้าทายข้างต้นทำให้ต้องปวดหัวกับการบำรุงรักษา เป็นเพราะเราต้องหาอินสแตนซ์ทั้งหมดแทนที่ด้วยชื่อใหม่ตัวเลือกและรหัสอื่น ๆ นอกจากนี้เรายังต้องใช้เวลามากมายเพื่อให้การทดสอบสอดคล้องกับการปรับโครงสร้างใหม่
การทดสอบเสีย
ความท้าทายอีกประการหนึ่งในการทดสอบ UI คือการเกิดความล้มเหลวมากมายในการทดสอบ
วิธีจัดการกับความท้าทาย
เราได้เห็นความท้าทายทั่วไปของการทดสอบ UI วิธีรับมือกับความท้าทายดังกล่าวมีดังนี้ -
การอัปเดตการอ้างอิงด้วยตนเอง
ตัวเลือกแรกในการจัดการกับความท้าทายข้างต้นคือการอัปเดตข้อมูลอ้างอิงด้วยตนเอง ปัญหาของตัวเลือกนี้คือเราต้องทำการเปลี่ยนแปลงโค้ดด้วยตนเองรวมทั้งการทดสอบของเรา สามารถทำได้เมื่อคุณมีไฟล์ทดสอบหนึ่งหรือสองไฟล์ แต่ถ้าคุณมีไฟล์ทดสอบหลายร้อยไฟล์ในโปรเจ็กต์ล่ะ?
การใช้ Page Objects
อีกทางเลือกหนึ่งสำหรับการจัดการความท้าทายข้างต้นคือการใช้วัตถุหน้า ออบเจ็กต์หน้าเป็น JavaScript ธรรมดาที่ห่อหุ้มคุณสมบัติของเทมเพลตเชิงมุม ตัวอย่างเช่นไฟล์ข้อมูลจำเพาะต่อไปนี้เขียนโดยไม่มีและด้วยวัตถุหน้าเพื่อให้เข้าใจความแตกต่าง -
Without Page Objects
describe('angularjs homepage', function() {
it('should greet the named user', function() {
browser.get('http://www.angularjs.org');
element(by.model('yourName')).sendKeys('Julie');
var greeting = element(by.binding('yourName'));
expect(greeting.getText()).toEqual('Hello Julie!');
});
});
With Page Objects
สำหรับการเขียนโค้ดด้วย Page Objects สิ่งแรกที่เราต้องทำคือการสร้าง Page Object ดังนั้น Page Object สำหรับตัวอย่างข้างต้นจึงมีลักษณะดังนี้ -
var AngularHomepage = function() {
var nameInput = element(by.model('yourName'));
var greeting = element(by.binding('yourName'));
this.get = function() {
browser.get('http://www.angularjs.org');
};
this.setName = function(name) {
nameInput.sendKeys(name);
};
this.getGreetingText = function() {
return greeting.getText();
};
};
module.exports = new AngularHomepage();
การใช้ Page Objects เพื่อจัดระเบียบการทดสอบ
เราได้เห็นการใช้ออบเจ็กต์หน้าในตัวอย่างข้างต้นเพื่อจัดการกับความท้าทายของการทดสอบ UI ต่อไปเราจะพูดถึงวิธีที่เราสามารถใช้เพื่อจัดระเบียบการทดสอบ สำหรับสิ่งนี้เราจำเป็นต้องแก้ไขสคริปต์ทดสอบโดยไม่ต้องแก้ไขการทำงานของสคริปต์ทดสอบ
ตัวอย่าง
เพื่อให้เข้าใจแนวคิดนี้เรากำลังใช้ไฟล์การกำหนดค่าข้างต้นพร้อมกับวัตถุหน้า เราจำเป็นต้องแก้ไขสคริปต์ทดสอบดังนี้ -
var angularHomepage = require('./AngularHomepage');
describe('angularjs homepage', function() {
it('should greet the named user', function() {
angularHomepage.get();
angularHomepage.setName('Julie');
expect(angularHomepage.getGreetingText()).toEqual
('Hello Julie!');
});
});
ที่นี่โปรดทราบว่าเส้นทางไปยังวัตถุเพจจะสัมพันธ์กับข้อกำหนดของคุณ
ในบันทึกเดียวกันเรายังสามารถแยกชุดทดสอบของเราออกเป็นชุดทดสอบต่างๆได้ จากนั้นไฟล์กำหนดค่าสามารถเปลี่ยนแปลงได้ดังนี้
exports.config = {
// The address of a running selenium server.
seleniumAddress: 'http://localhost:4444/wd/hub',
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
// Spec patterns are relative to the location of the spec file. They may
// include glob patterns.
suites: {
homepage: 'tests/e2e/homepage/**/*Spec.js',
search: ['tests/e2e/contact_search/**/*Spec.js',
'tests/e2e/venue_search/**/*Spec.js']
},
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true, // Use colors in the command line report.
}
};
ตอนนี้เราสามารถสลับระหว่างการเรียกใช้ชุดการทดสอบหนึ่งหรือชุดอื่น ๆ ได้อย่างง่ายดาย คำสั่งต่อไปนี้จะรันเฉพาะส่วนหน้าแรกของการทดสอบ -
protractor protractor.conf.js --suite homepage
ในทำนองเดียวกันเราสามารถเรียกใช้ชุดการทดสอบเฉพาะโดยใช้คำสั่งดังนี้ -
protractor protractor.conf.js --suite homepage,search
ไม้โปรแทรกเตอร์ - การดีบัก
ตอนนี้เราได้เห็นแนวคิดทั้งหมดของ Protractor ในบทก่อนหน้าแล้วให้เราเข้าใจแนวคิดการดีบักโดยละเอียดในบทนี้
บทนำ
การทดสอบแบบ end-to-end (e2e) นั้นยากที่จะแก้ไขข้อบกพร่องเนื่องจากขึ้นอยู่กับระบบนิเวศทั้งหมดของแอปพลิเคชันนั้น เราเห็นว่ามันขึ้นอยู่กับการกระทำต่างๆหรือโดยเฉพาะอย่างยิ่งเราสามารถพูดได้ว่าในการดำเนินการก่อนหน้านี้เช่นการเข้าสู่ระบบและบางครั้งก็ขึ้นอยู่กับการอนุญาต ความยากอีกประการหนึ่งในการดีบักการทดสอบ e2e คือการพึ่งพา WebDriver เนื่องจากทำหน้าที่แตกต่างกันไปตามระบบปฏิบัติการและเบราว์เซอร์ต่างๆ สุดท้ายการดีบักการทดสอบ e2e ยังสร้างข้อความแสดงข้อผิดพลาดที่ยาวและทำให้ยากที่จะแยกปัญหาที่เกี่ยวข้องกับเบราว์เซอร์และทดสอบข้อผิดพลาดของกระบวนการ
ประเภทของความล้มเหลว
อาจมีสาเหตุหลายประการสำหรับความล้มเหลวของชุดทดสอบและสิ่งต่อไปนี้เป็นประเภทความล้มเหลวที่รู้จักกันดี -
WebDriver ล้มเหลว
เมื่อไม่สามารถดำเนินการคำสั่ง WebDriver มีข้อผิดพลาด ตัวอย่างเช่นเบราว์เซอร์ไม่สามารถรับที่อยู่ที่กำหนดหรือไม่พบองค์ประกอบตามที่คาดไว้
WebDriver ล้มเหลวโดยไม่คาดคิด
เบราว์เซอร์ที่ไม่คาดคิดและความล้มเหลวที่เกี่ยวข้องกับระบบปฏิบัติการเกิดขึ้นเมื่อไม่สามารถอัปเดตตัวจัดการโปรแกรมควบคุมเว็บ
ไม้โปรแทรกเตอร์ล้มเหลวสำหรับ Angular
ความล้มเหลวของ Protractor สำหรับ Angular เกิดขึ้นเมื่อ Protractor ไม่พบ Angular ในไลบรารีตามที่คาดไว้
ไม้โปรแทรกเตอร์ Angular2 ล้มเหลว
ในความล้มเหลวประเภทนี้ไม้โปรแทรกเตอร์จะล้มเหลวเมื่อไม่พบพารามิเตอร์ useAllAngular2AppRoots ในคอนฟิกูเรชัน เกิดขึ้นเนื่องจากหากไม่มีสิ่งนี้กระบวนการทดสอบจะดูองค์ประกอบรูทเดียวเดียวในขณะที่คาดหวังว่าจะมีองค์ประกอบมากกว่าหนึ่งในกระบวนการ
ไม้โปรแทรกเตอร์ล้มเหลวสำหรับการหมดเวลา
ความล้มเหลวประเภทนี้เกิดขึ้นเมื่อข้อกำหนดการทดสอบเข้าสู่ลูปหรือพูลยาวและไม่สามารถส่งคืนข้อมูลได้ทันเวลา
ความคาดหวังล้มเหลว
หนึ่งในความล้มเหลวในการทดสอบที่พบบ่อยที่สุดซึ่งแสดงให้เห็นว่าความล้มเหลวของความคาดหวังตามปกติมีลักษณะอย่างไร
เหตุใดการดีบักจึงมีความสำคัญในไม้โปรแทรกเตอร์
สมมติว่าหากคุณเขียนกรณีทดสอบแล้วและเกิดข้อผิดพลาดเป็นเรื่องสำคัญมากที่จะต้องทราบวิธีการดีบักกรณีทดสอบเหล่านั้นเพราะจะเป็นการยากมากที่จะหาตำแหน่งที่แน่นอนที่เกิดข้อผิดพลาด ในขณะทำงานกับไม้โปรแทรกเตอร์คุณจะได้รับข้อผิดพลาดที่ยาวเป็นแบบอักษรสีแดงในบรรทัดคำสั่ง
การหยุดชั่วคราวและการดีบักการทดสอบ
วิธีการดีบักใน Protractor มีอธิบายไว้ที่นี่ & miuns;
วิธีหยุดชั่วคราว
การใช้วิธีหยุดชั่วคราวเพื่อดีบักกรณีทดสอบในไม้โปรแทรกเตอร์เป็นวิธีที่ง่ายที่สุดวิธีหนึ่ง เราสามารถพิมพ์คำสั่งต่อไปนี้ในตำแหน่งที่เราต้องการหยุดรหัสทดสอบของเราชั่วคราว & miuns;
browser.pause();
เมื่อรหัสที่ทำงานอยู่ตรงกับคำสั่งด้านบนรหัสดังกล่าวจะหยุดโปรแกรมที่กำลังทำงานชั่วคราว ณ จุดนั้น หลังจากนั้นเราสามารถให้คำสั่งต่อไปนี้ตามความต้องการของเรา -
พิมพ์ C เพื่อก้าวไปข้างหน้า
เมื่อใดก็ตามที่คำสั่งหมดลงเราต้องพิมพ์ C เพื่อก้าวไปข้างหน้า หากคุณไม่พิมพ์ C การทดสอบจะไม่รันโค้ดเต็มและจะล้มเหลวเนื่องจากข้อผิดพลาดหมดเวลาจัสมิน
พิมพ์ repl เพื่อเข้าสู่โหมดโต้ตอบ
ประโยชน์ของโหมดโต้ตอบคือเราสามารถส่งคำสั่ง WebDriver ไปยังเบราว์เซอร์ของเราได้ หากเราต้องการเข้าสู่โหมดโต้ตอบก็พิมพ์repl.
พิมพ์ Ctrl-C เพื่อออกและดำเนินการทดสอบต่อ
สำหรับการออกจากการทดสอบจากสถานะหยุดชั่วคราวและดำเนินการทดสอบต่อจากจุดที่หยุดไปเราต้องพิมพ์ Ctrl-C
ตัวอย่าง
ในตัวอย่างนี้เรามีไฟล์ข้อมูลจำเพาะด้านล่างชื่อ example_debug.jsไม้โปรแทรกเตอร์พยายามระบุองค์ประกอบด้วยตัวระบุตำแหน่ง by.binding('mmmm') แต่ URL (https://angularjs.org/ หน้าไม่มีองค์ประกอบที่มีตัวระบุตำแหน่งที่ระบุ
describe('Suite for protractor debugger',function(){
it('Failing spec',function(){
browser.get("http://angularjs.org");
element(by.model('yourName')).sendKeys('Vijay');
//Element doesn't exist
var welcomeText =
element(by.binding('mmmm')).getText();
expect('Hello '+welcomeText+'!').toEqual('Hello Ram!')
});
});
ตอนนี้สำหรับการดำเนินการทดสอบข้างต้นเราจำเป็นต้องเพิ่มรหัส browser.pause () ซึ่งคุณต้องการหยุดการทดสอบชั่วคราวในไฟล์ข้อมูลจำเพาะด้านบน จะมีลักษณะดังนี้ -
describe('Suite for protractor debugger',function(){
it('Failing spec',function(){
browser.get("http://angularjs.org");
browser.pause();
element(by.model('yourName')).sendKeys('Vijay');
//Element doesn't exist
var welcomeText =
element(by.binding('mmmm')).getText();
expect('Hello '+welcomeText+'!').toEqual('Hello Ram!')
});
});
แต่ก่อนที่จะดำเนินการเราจำเป็นต้องทำการเปลี่ยนแปลงบางอย่างในไฟล์กำหนดค่าด้วย เรากำลังทำการเปลี่ยนแปลงต่อไปนี้ในไฟล์คอนฟิกูเรชันที่ใช้ก่อนหน้านี้ชื่อexample_configuration.js ในบทที่แล้ว -
// An example configuration file.
exports.config = {
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'
},
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['example_debug.js'],
allScriptsTimeout: 999999,
jasmineNodeOpts: {
defaultTimeoutInterval: 999999
},
onPrepare: function () {
browser.manage().window().maximize();
browser.manage().timeouts().implicitlyWait(5000);
}
};
ตอนนี้เรียกใช้คำสั่งต่อไปนี้ -
protractor example_configuration.js
ดีบักเกอร์จะเริ่มทำงานหลังจากคำสั่งด้านบน
วิธีการดีบักเกอร์
การใช้วิธีหยุดชั่วคราวเพื่อดีบักกรณีทดสอบใน Protractor เป็นวิธีขั้นสูงเล็กน้อย เราสามารถพิมพ์คำสั่งต่อไปนี้ในสถานที่ที่เราต้องการทำลายรหัสทดสอบของเรา -
browser.debugger();
ใช้ดีบักเกอร์โหนดเพื่อดีบักโค้ดทดสอบ สำหรับการเรียกใช้คำสั่งดังกล่าวเราต้องพิมพ์คำสั่งต่อไปนี้ในพรอมต์คำสั่งแยกต่างหากซึ่งเปิดขึ้นจากตำแหน่งโครงการทดสอบ -
protractor debug protractor.conf.js
ในวิธีนี้เราต้องพิมพ์ C ในเทอร์มินัลเพื่อดำเนินการต่อรหัสทดสอบ แต่ตรงข้ามกับวิธีหยุดชั่วคราวในวิธีนี้จะต้องพิมพ์เพียงครั้งเดียว
ตัวอย่าง
ในตัวอย่างนี้เราใช้ไฟล์ข้อมูลจำเพาะเดียวกันชื่อ bexample_debug.jsใช้ข้างต้น ข้อแตกต่างเพียงอย่างเดียวคือแทนที่จะเป็นbrowser.pause()เราจำเป็นต้องใช้ browser.debugger()ที่เราต้องการทำลายรหัสทดสอบ จะมีลักษณะดังนี้ -
describe('Suite for protractor debugger',function(){
it('Failing spec',function(){
browser.get("http://angularjs.org");
browser.debugger();
element(by.model('yourName')).sendKeys('Vijay');
//Element doesn't exist
var welcomeText = element(by.binding('mmmm')).getText();
expect('Hello '+welcomeText+'!').toEqual('Hello Ram!')
});
});
เรากำลังใช้ไฟล์กำหนดค่าเดียวกัน example_configuration.jsใช้ในตัวอย่างข้างต้น
ตอนนี้เรียกใช้การทดสอบไม้โปรแทรกเตอร์ด้วยตัวเลือกบรรทัดคำสั่งดีบักต่อไปนี้
protractor debug example_configuration.js
ดีบักเกอร์จะเริ่มทำงานหลังจากคำสั่งด้านบน
ไม้โปรแทรกเตอร์ - คู่มือสไตล์สำหรับไม้โปรแทรกเตอร์
ในบทนี้ให้เราเรียนรู้รายละเอียดเกี่ยวกับคู่มือสไตล์สำหรับไม้โปรแทรกเตอร์
บทนำ
คู่มือสไตล์สร้างขึ้นโดยวิศวกรซอฟต์แวร์สองคนชื่อ Carmen Popoviciuวิศวกรส่วนหน้าของ ING และ Andres Dominguezวิศวกรซอฟต์แวร์ของ Google ดังนั้นคำแนะนำสไตล์นี้จึงเรียกอีกอย่างว่า Carmen Popoviciu และคู่มือสไตล์ของ Google สำหรับไม้โปรแทรกเตอร์
คู่มือรูปแบบนี้สามารถแบ่งออกเป็นห้าประเด็นสำคัญต่อไปนี้ -
- กฎทั่วไป
- โครงสร้างโครงการ
- กลยุทธ์การระบุตำแหน่ง
- วัตถุหน้า
- ชุดทดสอบ
กฎทั่วไป
ต่อไปนี้เป็นกฎทั่วไปบางประการที่ต้องได้รับการดูแลในขณะที่ใช้ไม้โปรแทรกเตอร์ในการทดสอบ -
อย่าทดสอบแบบ end-to-end สิ่งที่ได้รับการทดสอบหน่วยแล้ว
นี่เป็นกฎทั่วไปข้อแรกที่กำหนดโดย Carmen และ Andres พวกเขาแนะนำว่าเราต้องไม่ทำการทดสอบ e2e กับรหัสที่ได้รับการทดสอบหน่วยแล้ว สาเหตุหลักคือการทดสอบหน่วยเร็วกว่าการทดสอบ e2e มาก อีกเหตุผลหนึ่งคือเราต้องหลีกเลี่ยงการทดสอบซ้ำ (อย่าทำการทดสอบทั้งหน่วยและ e2e) เพื่อประหยัดเวลาของเรา
ใช้ไฟล์กำหนดค่าเพียงไฟล์เดียว
จุดสำคัญอีกประการหนึ่งที่แนะนำคือเราต้องใช้ไฟล์กำหนดค่าเพียงไฟล์เดียว อย่าสร้างไฟล์คอนฟิกูเรชันสำหรับแต่ละสภาพแวดล้อมที่คุณกำลังทดสอบ คุณสามารถใช้ได้grunt-protractor-coverage เพื่อตั้งค่าสภาพแวดล้อมที่แตกต่างกัน
หลีกเลี่ยงการใช้ตรรกะในการทดสอบของคุณ
เราต้องหลีกเลี่ยงการใช้คำสั่ง IF หรือ FOR ลูปในกรณีทดสอบของเราเพราะหากทำเช่นนั้นการทดสอบอาจผ่านไปโดยไม่ต้องทดสอบอะไรเลยหรืออาจทำงานช้ามาก
ทำให้การทดสอบเป็นอิสระในระดับไฟล์
ไม้โปรแทรกเตอร์สามารถรันการทดสอบพร้อมกันเมื่อเปิดใช้งานการแชร์ จากนั้นไฟล์เหล่านี้จะถูกเรียกใช้งานในเบราว์เซอร์ต่างๆและเมื่อพร้อมใช้งาน Carmen และ Andres แนะนำให้ทำการทดสอบอย่างอิสระอย่างน้อยในระดับไฟล์เนื่องจากลำดับที่จะเรียกใช้โดยไม้โปรแทรกเตอร์นั้นไม่แน่นอนและยิ่งไปกว่านั้นมันค่อนข้างง่ายที่จะเรียกใช้การทดสอบแยกต่างหาก
โครงสร้างโครงการ
ประเด็นสำคัญอีกประการหนึ่งเกี่ยวกับแนวทางรูปแบบของไม้โปรแทรกเตอร์คือโครงสร้างของโครงการของคุณ ต่อไปนี้เป็นคำแนะนำเกี่ยวกับโครงสร้างโครงการ -
การทดสอบ e2e ในโครงสร้างที่เหมาะสม
Carmen และ Andres แนะนำว่าเราต้องจัดกลุ่มการทดสอบ e2e ของเราในโครงสร้างที่เหมาะสมกับโครงสร้างของโครงการของคุณ เหตุผลที่อยู่เบื้องหลังคำแนะนำนี้คือการค้นหาไฟล์จะกลายเป็นเรื่องง่ายและโครงสร้างโฟลเดอร์จะอ่านได้ง่ายขึ้น ขั้นตอนนี้จะแยกการทดสอบ e2e ออกจากการทดสอบหน่วย พวกเขาแนะนำว่าควรหลีกเลี่ยงโครงสร้างประเภทต่อไปนี้ -
|-- project-folder
|-- app
|-- css
|-- img
|-- partials
home.html
profile.html
contacts.html
|-- js
|-- controllers
|-- directives
|-- services
app.js
...
index.html
|-- test
|-- unit
|-- e2e
home-page.js
home-spec.js
profile-page.js
profile-spec.js
contacts-page.js
contacts-spec.js
ในทางกลับกันพวกเขาแนะนำโครงสร้างประเภทต่อไปนี้ -
|-- project-folder
|-- app
|-- css
|-- img
|-- partials
home.html
profile.html
contacts.html
|-- js
|-- controllers
|-- directives
|-- services
app.js
...
index.html
|-- test
|-- unit
|-- e2e
|-- page-objects
home-page.js
profile-page.js
contacts-page.js
home-spec.js
profile-spec.js
contacts-spec.js
กลยุทธ์การระบุตำแหน่ง
ต่อไปนี้เป็นกลยุทธ์การระบุตำแหน่งที่ต้องได้รับการดูแลในขณะที่ใช้ไม้โปรแทรกเตอร์ในการทดสอบ -
ห้ามใช้ XPATH
นี่เป็นกลยุทธ์การระบุตำแหน่งแรกที่แนะนำในคู่มือสไตล์ไม้โปรแทรกเตอร์ เหตุผลที่อยู่เบื้องหลังก็คือ XPath ต้องการการบำรุงรักษาเป็นจำนวนมากเนื่องจากมาร์กอัปสามารถเปลี่ยนแปลงได้ง่ายมาก ยิ่งไปกว่านั้นนิพจน์ XPath นั้นช้าที่สุดและยากที่จะดีบัก
มักจะชอบตัวระบุตำแหน่งเฉพาะของไม้โปรแทรกเตอร์เช่น by.model และ by.binding
ตัวระบุตำแหน่งเฉพาะของไม้โปรแทรกเตอร์เช่น by.model และ by.binding สั้นเฉพาะและอ่านง่าย ด้วยความช่วยเหลือของพวกเขามันง่ายมากที่จะเขียนที่ตั้งของเราด้วย
ตัวอย่าง
View
<ul class = "red">
<li>{{color.name}}</li>
<li>{{color.shade}}</li>
<li>{{color.code}}</li>
</ul>
<div class = "details">
<div class = "personal">
<input ng-model = "person.name">
</div>
</div>
สำหรับรหัสข้างต้นขอแนะนำให้หลีกเลี่ยงสิ่งต่อไปนี้ -
var nameElement = element.all(by.css('.red li')).get(0);
var personName = element(by.css('.details .personal input'));
ในทางกลับกันแนะนำให้ใช้สิ่งต่อไปนี้ -
var nameElement = element.all(by.css('.red li')).get(0);
var personName = element(by.css('.details .personal input'));
var nameElement = element(by.binding('color.name'));
var personName = element(by.model('person.name'));
เมื่อไม่มีตัวระบุตำแหน่งไม้โปรแทรกเตอร์แนะนำให้เลือก by.id และ by.css
หลีกเลี่ยงตัวระบุตำแหน่งข้อความเสมอสำหรับการเปลี่ยนแปลงข้อความบ่อยๆ
เราต้องหลีกเลี่ยงตัวระบุตำแหน่งแบบข้อความเช่น by.linkText, by.buttonText และ by.cssContaningText เนื่องจากข้อความสำหรับปุ่มลิงก์และป้ายกำกับมักมีการเปลี่ยนแปลงตลอดเวลา
วัตถุหน้า
ตามที่กล่าวไว้ก่อนหน้านี้ออบเจ็กต์ของหน้าจะสรุปข้อมูลเกี่ยวกับองค์ประกอบในหน้าแอปพลิเคชันของเราและด้วยเหตุนี้จึงช่วยให้เราเขียนกรณีทดสอบที่สะอาดขึ้น ข้อได้เปรียบที่มีประโยชน์มากของออบเจ็กต์เพจคือสามารถใช้ซ้ำได้ในการทดสอบหลาย ๆ ครั้งและในกรณีที่เทมเพลตของแอปพลิเคชันของเรามีการเปลี่ยนแปลงเราจำเป็นต้องอัปเดตออบเจ็กต์ของเพจเท่านั้น ต่อไปนี้เป็นคำแนะนำบางประการสำหรับออบเจ็กต์ของเพจที่ต้องได้รับการดูแลในขณะที่ใช้ไม้โปรแทรกเตอร์ในการทดสอบ -
ในการโต้ตอบกับเพจภายใต้การทดสอบให้ใช้ออบเจ็กต์เพจ
ขอแนะนำให้ใช้ออบเจ็กต์เพจเพื่อโต้ตอบกับเพจที่อยู่ระหว่างการทดสอบเนื่องจากสามารถสรุปข้อมูลเกี่ยวกับองค์ประกอบบนเพจที่อยู่ระหว่างการทดสอบและสามารถนำมาใช้ซ้ำได้ด้วย
ประกาศออบเจ็กต์หน้าเดียวต่อไฟล์เสมอ
เราควรกำหนดออบเจ็กต์แต่ละหน้าในไฟล์ของตัวเองเพราะมันช่วยให้โค้ดสะอาดและการค้นหาสิ่งต่างๆจะกลายเป็นเรื่องง่าย
ในตอนท้ายของไฟล์อ็อบเจ็กต์เพจจะใช้ module.exports เดียวเสมอ
ขอแนะนำว่าแต่ละออบเจ็กต์เพจควรประกาศคลาสเดียวเพื่อที่เราจะต้องเอ็กซ์พอร์ตคลาสเดียวเท่านั้น ตัวอย่างเช่นควรหลีกเลี่ยงการใช้อ็อบเจ็กต์ไฟล์ต่อไปนี้ -
var UserProfilePage = function() {};
var UserSettingsPage = function() {};
module.exports = UserPropertiesPage;
module.exports = UserSettingsPage;
แต่ในทางกลับกันแนะนำให้ใช้ต่อไปนี้ -
/** @constructor */
var UserPropertiesPage = function() {};
module.exports = UserPropertiesPage;
ประกาศโมดูลที่จำเป็นทั้งหมดที่ด้านบน
เราควรประกาศโมดูลที่จำเป็นทั้งหมดที่ด้านบนของออบเจ็กต์เพจเนื่องจากทำให้การอ้างอิงโมดูลชัดเจนและง่ายต่อการค้นหา
สร้างอินสแตนซ์ออบเจ็กต์หน้าทั้งหมดที่จุดเริ่มต้นของชุดทดสอบ
ขอแนะนำให้สร้างอินสแตนซ์ของออบเจ็กต์หน้าทั้งหมดที่จุดเริ่มต้นของชุดทดสอบเนื่องจากจะแยกการอ้างอิงออกจากรหัสทดสอบรวมทั้งทำให้การอ้างอิงพร้อมใช้งานสำหรับข้อกำหนดทั้งหมดของชุด
อย่าใช้คาดหวัง () ในวัตถุหน้า
เราไม่ควรใช้ expect () ในออบเจ็กต์ของเพจเช่นเราไม่ควรทำการยืนยันใด ๆ ในออบเจ็กต์หน้าของเราเนื่องจากการยืนยันทั้งหมดจะต้องทำในกรณีทดสอบ
อีกเหตุผลหนึ่งคือผู้อ่านการทดสอบควรสามารถเข้าใจพฤติกรรมของแอปพลิเคชันโดยการอ่านกรณีทดสอบเท่านั้น