JavaScript เป็นภาษาประเภทไดนามิกซึ่งให้ความสามารถในการทำงานที่แข็งแกร่งของเธอ แต่ยังทำให้คอมไพเลอร์แทบจะเป็นไปไม่ได้ที่จะให้ความช่วยเหลือแก่นักพัฒนา ด้วยเหตุนี้เราจึงรู้สึกว่าการเขียนรหัส JavaScript ใด ๆ จะต้องมีชุดทดสอบที่ทรงพลังและสมบูรณ์ Angular มีคุณสมบัติมากมายที่ทำให้เราสามารถทดสอบแอปพลิเคชันของเราได้ง่ายขึ้น เราไม่ควรมีข้อแก้ตัวที่จะไม่เขียนการทดสอบ (นี่คือ ... )
1. มันคือทั้งหมดที่เกี่ยวกับการผสมข้อกังวล (มันคือทั้งหมดที่เกี่ยวกับการหลีกเลี่ยงความสัมพันธ์ของรหัสมีความซับซ้อน ... )
การทดสอบหน่วยเป็นชื่อเกี่ยวกับการทดสอบ "หน่วย" เดียว การทดสอบหน่วยมุ่งมั่นที่จะตอบคำถามเหล่านี้: ฉันถูกต้องแล้วในการพิจารณาตรรกะของฉันหรือไม่? ผลลัพธ์ที่ได้จากวิธีการเรียงลำดับถูกต้องหรือไม่? เพื่อตอบคำถามเหล่านี้เป็นสิ่งสำคัญอย่างยิ่งที่จะต้องแยกพวกเขาออก นี่เป็นเพราะเมื่อเราทดสอบวิธีการเรียงลำดับเราไม่ต้องการสนใจชิ้นส่วนที่เกี่ยวข้องอื่น ๆ เช่นองค์ประกอบ DOM หรือเริ่มต้นคำขอ XHR เพื่อรับข้อมูล ฯลฯ เห็นได้ชัดว่ามันยากที่จะเรียกฟังก์ชันแยกต่างหากในโครงการทั่วไป สิ่งที่ทำให้เกิดปัญหานี้คือนักพัฒนามักจะทำให้ความสัมพันธ์ซับซ้อนและจบลงด้วยการทำให้ตัวอย่างดูเหมือนว่ามันสามารถทำทุกอย่างได้ มันได้รับข้อมูลผ่าน XHR เรียงลำดับข้อมูลแล้วจัดการกับ DOM เมื่อรวมกับ Angular เราสามารถเขียนโค้ดที่ดีขึ้นได้ง่ายขึ้นดังนั้น Angular จึงช่วยให้เราได้รับการพึ่งพา XHR (ซึ่งเราสามารถจำลองได้) และ Angular ยังสร้าง abstractions ที่ช่วยให้เราจัดเรียงแบบจำลองโดยไม่ต้องจัดการกับ DOM ดังนั้นในตอนท้ายเราสามารถเขียนวิธีการเรียงลำดับจากนั้นสร้างชุดข้อมูลผ่านกรณีทดสอบสำหรับวิธีการเรียงลำดับที่จะใช้เมื่อทำการทดสอบแล้วพิจารณาว่าโมเดลผลลัพธ์ตรงกับความคาดหวังหรือไม่ การทดสอบไม่จำเป็นต้องรอให้ XHR สร้าง DOM ที่เกี่ยวข้องและพิจารณาว่าฟังก์ชั่นทำงาน DOM อย่างถูกต้องหรือไม่ แนวคิดหลักของ Angular รวมถึงความสามารถในการทดสอบของรหัส แต่ยังต้องการให้เราทำสิ่งที่ถูกต้อง Angular มุ่งมั่นที่จะทำให้วิธีการทำสิ่งที่ถูกต้องง่ายขึ้น แต่ Angular ไม่ใช่เวทมนตร์ซึ่งหมายความว่าเราอาจจบลงด้วยแอปพลิเคชันที่ไม่สามารถคาดเดาได้หากเราไม่ทำตามประเด็นต่อไปนี้
1. การพึ่งพา
มีหลายวิธีในการรับทรัพยากรการพึ่งพา: 1) เราสามารถใช้ผู้ให้บริการใหม่ได้ 2) เราใช้วิธีการที่รู้จักกันดีที่เรียกว่า "Global Singleton"; 3) เราสามารถขอได้จากบริการรีจิสทรี (แต่เราจะได้รับรีจิสทรีได้อย่างไรคุณสามารถตรวจสอบบทต่อไปนี้ได้); 4) เราสามารถคาดหวังได้ว่าจะผ่านไป
ของวิธีการที่ระบุไว้ข้างต้นมีเพียงวิธีสุดท้ายเท่านั้นที่สามารถทดสอบได้มาดูกันว่าทำไม:
1) การใช้ตัวดำเนินการใหม่
โดยทั่วไปไม่มีข้อผิดพลาดเมื่อใช้ตัวดำเนินการใหม่ แต่ปัญหาคือการเรียกตัวสร้างผ่านใหม่จะผูกผู้โทรเข้ากับประเภทอย่างถาวร ตัวอย่างเช่นเราพยายามสร้างอินสแตนซ์วัตถุ XHR เพื่อให้เราสามารถรับข้อมูลจากเซิร์ฟเวอร์ได้
ฟังก์ชั่น myclass () {this.dowork = function () {var xhr = new xrh (); xhr.open (วิธีการ, url, true); xhr.onreadyStateChange = function () {…}; xhr.send (); -ปัญหาคือเมื่อทำการทดสอบเรามักจะต้องยกตัวอย่าง XHR เสมือนจริงที่สามารถส่งคืนข้อมูลการทดสอบหรือข้อผิดพลาดของเครือข่าย โดยการโทรหา XHR ใหม่ () เราจะผูก XHR จริงอย่างถาวรและไม่มีวิธีที่ดีในการแทนที่ แน่นอนว่ามีวิธีการรักษาที่ไม่ดีและมีเหตุผลหลายประการที่จะพิสูจน์ว่ามันเป็นความคิดที่ไม่ดี:
var oldxhr = xhr; xhr = new mockxhr () {}; myclass.dowork (); // ตัดสินว่า mockxhr เรียกว่า xhr = oldxhr ผ่านพารามิเตอร์ปกติ; // ถ้าคุณลืมขั้นตอนนี้หรือไม่2) การค้นหาทั่วโลก
อีกวิธีหนึ่งในการแก้ปัญหาคือการได้รับทรัพยากรการพึ่งพาในสถานที่ที่รู้จักกันดี
ฟังก์ชั่น myclass () {this.dowork = function () {global.xhr ({…}); -โดยไม่ต้องสร้างอินสแตนซ์ของวัตถุที่ขึ้นอยู่กับใหม่ปัญหานั้นเหมือนกับใหม่และไม่มีวิธีที่ดีในการสกัดกั้นการโทร global.xhr เมื่อทำการทดสอบ ปัญหาพื้นฐานที่สุดเกี่ยวกับการทดสอบคือตัวแปรทั่วโลกจะต้องเปลี่ยนเพื่อเรียกใช้วิธีการเสมือนจริงและได้รับการแก้ไข หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับข้อเสียของมันเยี่ยมชมที่นี่: http://misko.hevery.com/code-reviewers-guide/flaw-britte-global-state-singletons/
รหัสข้างต้นเป็นการยากที่จะทดสอบดังนั้นเราต้องแก้ไขสถานะทั่วโลก:
var oldxhr = global.xhr; global.xhr = ฟังก์ชั่น mockxhr () {…}; var myclass = new myclass (); // ตัดสินว่า mockxhr เรียก global.xhr = oldxhr ผ่านพารามิเตอร์ปกติหรือไม่ถ้าคุณลืมขั้นตอนนี้3) บริการรีจิสทรี
การมีรีจิสทรีที่มีบริการทั้งหมดดูเหมือนจะแก้ปัญหาแล้วแทนที่บริการที่ต้องการในรหัสทดสอบ
ฟังก์ชั่น myclass () {var serviceregistry = ???; this.dowork = function () {var xhr = serviceregistry.get ("xhr"); -แต่ Serviceregistry มาจากไหน? หากเป็น: * ใหม่ขึ้นการทดสอบไม่มีโอกาสรีเซ็ตบริการสำหรับการทดสอบ * การค้นหาทั่วโลกจากนั้นบริการที่ส่งคืนนั้นเป็นระดับโลกเช่นกัน (แต่การรีเซ็ตง่ายขึ้นเนื่องจากมีตัวแปรระดับโลกเพียงตัวเดียวเท่านั้นที่จะรีเซ็ต) (ข้อความที่อยู่เบื้องหลัง
ตามวิธีนี้แก้ไขคลาสข้างต้นเป็นวิธีการต่อไปนี้:
var oldservicelocator = global.servicelocator; global.servicelocator.set ('xhr', ฟังก์ชั่น mockxhr () {}); var myclass = new myclass (); myclass.dowork (); // ถ้าคุณลืมขั้นตอนนี้มันเป็นเรื่องง่ายที่จะทำให้เกิดสิ่งที่น่าเศร้า4) ผ่านการพึ่งพา
ในที่สุดทรัพยากรการพึ่งพาสามารถส่งผ่านได้
ฟังก์ชั่น myclass (xhr) {this.dowork = function () {xhr ({…}); -นี่เป็นวิธีที่ต้องการเนื่องจากรหัสไม่จำเป็นต้องให้ความสนใจกับที่ XHR มาจากไหนและไม่สนใจว่าใครจะสร้าง XHR ที่ผ่านเข้ามาดังนั้นผู้สร้างชั้นเรียนสามารถเข้ารหัสแยกต่างหากจากผู้บริโภคในชั้นเรียนซึ่งแยกความรับผิดชอบของการสร้างจากตรรกะ
คลาสนี้ง่ายต่อการทดสอบและเราสามารถเขียนได้เช่นนี้ในการทดสอบ:
ฟังก์ชั่น xhrmock (args) {…} var myclass = new myclass (xhrmock); myclass.dowrok (); // ทำการตัดสินบางอย่าง ... ผ่านรหัสทดสอบนี้เราสามารถตระหนักได้ว่าไม่มีตัวแปรทั่วโลกเสียหายการพึ่งพาการฉีด (//www.vevb.com/article/91775.htm) รวมถึง Angular รหัสที่เขียนด้วยวิธีนี้ทำให้ง่ายต่อการเขียนรหัสทดสอบ หากเราต้องการเขียนโค้ดที่สามารถทดสอบได้สูงเราควรใช้งานได้ดีกว่า
2. คอนโทรลเลอร์
ตรรกะทำให้ทุกแอปพลิเคชันไม่เหมือนใครและนั่นคือสิ่งที่เราต้องการทดสอบ หากตรรกะของเราผสมกับการดำเนินงาน DOM นี่จะเป็นการยากที่จะทดสอบเป็นตัวอย่างต่อไปนี้:
ฟังก์ชั่น PasswordController () {// รับการอ้างอิงไปยังวัตถุ DOM var msg = $ ('. ex1 span'); var input = $ ('. ex1 input'); ความแข็งแรงของ var; this.grade = function () {msg.removeclass (ความแข็งแรง); var pwd = input.val (); รหัสผ่านข้อความ (PWD); if (pwd.length> 8) {strength = 'strong'; } อื่นถ้า (pwd.length> 3) {strength = 'medium'; } else {strength = 'อ่อนแอ'; } msg.addclass (Strength) .Text (Strength); -รหัสข้างต้นจะพบปัญหาเมื่อทำการทดสอบเพราะต้องการให้เรามี DOM ที่ถูกต้องเมื่อดำเนินการทดสอบ รหัสทดสอบจะมีดังนี้:
var input = $ ('<input type = "text"/>'); var span = $ ('<span>'); $ ('body'). html ('<div>') ค้นหา ('div'). ผนวก (อินพุต) PasswordController (); input.val ('abc'); pc.grade (); คาดหวัง (span.text ()). toequal ('อ่อนแอ'); $ ('body'). html ('');ใน Angular คอนโทรลเลอร์จะแยกตรรกะการทำงานของ DOM อย่างเคร่งครัดซึ่งจะลดความยากลำบากในการเขียนกรณีทดสอบอย่างมาก ดูตัวอย่างต่อไปนี้:
ฟังก์ชั่นรหัสผ่าน cntrl ($ scope) {$ scope.password = ''; $ scope.grade = function () {var size = $ spope.password.length; if (ขนาด> 8) {$ scope.strength = 'strong'; } อื่นถ้า (ขนาด> 3) {$ scope.strength = 'medium'; } else {$ scope.strength = 'อ่อนแอ'; -รหัสทดสอบตรงไปตรงมา:
var pc = new passwordController ($ scope); pc.password ('abc'); pc.grade (); คาดหวัง ($ scope.strength) .toequal ('อ่อนแอ');เป็นที่น่าสังเกตว่ารหัสทดสอบไม่เพียง แต่ไม่ต่อเนื่องมากขึ้นเท่านั้น แต่ยังง่ายต่อการติดตาม เราได้กล่าวเสมอว่ากรณีทดสอบกำลังบอกเล่าเรื่องราวไม่ใช่การตัดสินสิ่งที่ไม่เกี่ยวข้องอื่น ๆ
3. ตัวกรอง
ตัวกรอง (http://docs.angularjs.org/api/ng.$filter) ใช้เพื่อแปลงข้อมูลเป็นรูปแบบที่ใช้งานง่าย พวกเขามีความสำคัญเนื่องจากพวกเขาแยกความรับผิดชอบของการแปลงรูปแบบจากตรรกะแอปพลิเคชันซึ่งทำให้ตรรกะแอปพลิเคชันง่ายขึ้น
myModule.filter ('ความยาว', ฟังก์ชัน () {ฟังก์ชั่นส่งคืน (ข้อความ) {return (''+(ข้อความ || '')). ความยาว;}}); ความยาว var = $ filter ('ความยาว'); คาดหวัง (ความยาว (null)). toequal (0);4. คำสั่ง
5. เยาะเย้ย
6. การแยกรัฐทั่วโลก
7. วิธีการทดสอบที่ต้องการ
8. JavaScriptTestDriver
9. จัสมิน
10. ตัวอย่างโครงการ
เราจะอัปเดตบทความที่เกี่ยวข้องต่อไปในอนาคต ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!