การทดสอบ js การทดสอบความรู้ JavaScript - พื้นฐาน

เพื่อนของฉันคนหนึ่งเคยแสดงความงุนงงว่าจาวาสคริปต์สามารถใช้เขียนผลิตภัณฑ์ระดับองค์กรอย่างจริงจังได้อย่างไร เพราะไม่มีคอมไพเลอร์ ในความเป็นจริงแล้ว บทบาทชี้ขาดในการสร้างโค้ดคุณภาพสูงนั้นไม่ได้เกิดจากการมีคอมไพเลอร์สำหรับภาษาโปรแกรม แต่มาจากกระบวนการทางเทคนิคที่ได้รับเลือกอย่างถูกต้องและปรับแต่งอย่างดีสำหรับการสร้างระบบซอฟต์แวร์

กระบวนการนี้ควรมีชุดเครื่องมือควบคุมคุณภาพและประสิทธิภาพสำหรับโปรแกรมเมอร์ เครื่องมือดังกล่าวสามารถเป็น: การทดสอบหน่วยและการรวม การรวมอย่างต่อเนื่อง (การรวมอย่างต่อเนื่อง CI) การรวบรวมและการวิเคราะห์เมตริกต่างๆ (เช่น วิธีการที่ยาวมากใน nDepend) การตรวจสอบการปฏิบัติตามข้อกำหนดของ JsLint, FxCop เป็นต้น

ในบทความนี้ ฉันต้องการบอกวิธีดำเนินการทดสอบหน่วยอัตโนมัติและการรวมผลิตภัณฑ์ของคุณใน JavaScript อย่างถูกต้อง อันที่จริง JavaScript ก็ไม่ต่างจาก Java หรือ C# ในแง่นี้

เปรียว TDD และ BDD

โดยทั่วไป แนะนำให้สร้างหน่วยอัตโนมัติและการทดสอบการรวมสำหรับฟังก์ชันที่ดำเนินการ เพื่อลดความเสี่ยงของข้อผิดพลาดในการถดถอยเมื่อเปลี่ยนรหัสในอนาคต ในกรณีของ JavaScript การทดสอบเหล่านี้ช่วยให้ตรวจสอบได้ง่ายขึ้นว่าระบบทำงานในเบราว์เซอร์ต่างๆ ได้โดยทำตามขั้นตอนอัตโนมัติเพื่อให้แน่ใจว่าใช้งานได้ นอกจากนี้ การเขียนหน่วยหรือการทดสอบการรวมระบบสำหรับจุดบกพร่องที่ปิดแล้วในผลิตภัณฑ์สามารถให้บริการที่ดีได้

นอกจากนี้ยังมีเทคนิคการเขียนโปรแกรมที่ทำให้คุณต้องเริ่มโค้ดโค้ดด้วยการเขียนการทดสอบหน่วย: Test-Driven Development (TDD) และ Behavior-Driven Development (BDD) มักใช้ในกระบวนการ Agile ลองพิจารณาคุณสมบัติของพวกเขาโดยละเอียด

ทดสอบการขับเคลื่อนการพัฒนา

การพัฒนาโดยใช้การทดสอบคือกระบวนการเขียนโค้ดแบบวนซ้ำซึ่งทำซ้ำสี่ขั้นตอนต่อไปนี้:

ขั้นตอนที่ 1. ก่อนเพิ่มตรรกะชิ้นใหม่ ให้สร้างการทดสอบหน่วยเพื่อทดสอบตรรกะนั้น

ขั้นตอนที่ 2. เรียกใช้การทดสอบและตรวจสอบให้แน่ใจ ไม่ผ่าน;

ขั้นตอนที่ 3. เขียนรหัสที่ง่ายที่สุดที่จะทำให้การทดสอบผ่าน

ขั้นตอนที่ 4. แก้ไขโค้ดตามข้อกำหนดด้านคุณภาพ ลบโค้ดที่ซ้ำกัน และตรวจสอบให้แน่ใจว่าการทดสอบผ่าน

การทดสอบหน่วยเป็นรหัสที่ทดสอบการทำงานของส่วนประกอบ (โมดูล) บางส่วนในสภาพแวดล้อมที่แยกจากกัน การทดสอบการรวมเป็นรหัสที่ทดสอบ ทำงานร่วมกันหลายองค์ประกอบ การทดสอบสองเท่าใช้เพื่อทดสอบโมดูลในสภาพแวดล้อมที่แยกจากกันเมื่อขึ้นอยู่กับโมดูลอื่น

ทดสอบคู่

การแบ่งวัตถุเสริมที่ใช้ในการทดสอบหน่วยเป็นหมวดหมู่มาจากหนังสือ xUnit Test Patterns โดย Gerard Meszaros หมวดหมู่เหล่านี้เรียกรวมกันว่า "คู่ทดสอบ" (คู่ทดสอบ) Doublers เป็นประเภทต่อไปนี้:

  • ปลอม;
  • ดัมมี่

ต้นขั้ว ค่าเอาต์พุตซึ่งกำหนดไว้ล่วงหน้า ใช้เพื่อเลียนแบบอินเทอร์เฟซของส่วนประกอบที่ขึ้นต่อกัน

ล้อเลียนเป็นวัตถุตัวช่วย พฤติกรรมซึ่งกำหนดไว้ล่วงหน้า ใช้เพื่อเลียนแบบส่วนต่อประสานของส่วนประกอบที่ขึ้นต่อกัน และทดสอบว่าใช้อย่างถูกต้องในระหว่างการทดสอบหรือไม่

สอดแนมเป็นอ็อบเจกต์ตัวช่วยสำหรับตรวจสอบเมธอดที่เรียกใช้และพารามิเตอร์ที่ส่งผ่านไปยังเมธอดระหว่างการทดสอบ

ปลอมเป็นวัตถุตัวช่วยที่ใช้อินเทอร์เฟซของส่วนประกอบที่ขึ้นต่อกันในรูปแบบที่เรียบง่าย ตัวอย่างเช่น สำหรับวัตถุประสงค์ในการทดสอบหน่วย คุณสามารถมีฐานข้อมูลในหน่วยความจำแทนฐานข้อมูลเชิงสัมพันธ์ที่ใช้ในเวอร์ชันที่ใช้งานจริงของผลิตภัณฑ์

ดัมมี่เป็นอ็อบเจกต์ตัวช่วยที่มีการบ่งชี้หรือการผ่านที่จำเป็นโดยลายเซ็นวิธีการหรือสัญญาอื่น ๆ แต่ไม่เคยใช้ค่าจริง

ความแตกต่างระหว่าง Stub และ Mock คือวิธีการยืนยันผลการทดสอบ ในกรณีของ Stub สถานะของวัตถุจะถูกตรวจสอบเมื่อสิ้นสุดการทดสอบ ในกรณีของ Mock การทดสอบจะตรวจสอบว่ามีการใช้วัตถุตรงตามที่อธิบายไว้ในระหว่างการลงทะเบียนหรือไม่ สามารถดูรายละเอียดได้ในหมายเหตุ Mocks Aren "t Stubs โดย Martin Fowler และฉันจะยกตัวอย่างที่นี่

ต้นขั้ว ล้อเลียน
"การทดสอบการเชื่อมต่อควรเริ่มการสำรวจ": function () ( this.client.url = "/my/url"; sinon.stub(ajax, "poll").returns(()); this.client.connect(); sinon.assert.calledWith(ajax.poll, "/my/url"); ) "การทดสอบการเชื่อมต่อควรเริ่มการสำรวจ": function () ( this.client.url = "/my/url"; var mock = sinon.mock(ajax) mock.expects("poll") .withArgs("/my/url ").returns(()); this.client.connect(); mock.verify(); )

การพัฒนาพฤติกรรมขับเคลื่อน

แนวทางการพัฒนาซ้ำๆ ซอฟต์แวร์ผ่านการดำเนินการตามข้อกำหนดด้านการทำงาน ซึ่งเป็นรูปแบบที่คุ้นเคยอยู่แล้วของการพัฒนาเพื่อการทดสอบที่เน้นผลลัพธ์ สามขั้นตอนต่อไปนี้ถูกปฏิบัติตามตามลำดับในกระบวนการ BDD:

ขั้นตอนที่ 1. คำจำกัดความของข้อกำหนดการทำงานสำหรับโมดูลที่ดำเนินการในรูปแบบของการทดสอบ

ขั้นตอนที่ 2. การเข้ารหัสโมดูล

ขั้นตอนที่ 3. การตรวจสอบว่าเป็นไปตามความปรารถนาทั้งหมดของลูกค้าหรือนักวิเคราะห์ธุรกิจ () โดยการตรวจสอบผลการทดสอบที่กำลังรันอยู่

เมื่อเขียนแบบทดสอบในรูปแบบ BDD จะสะดวกมากที่จะใช้วัตถุจำลองเนื่องจากสะท้อนถึงข้อกำหนดการทำงานสำหรับส่วนประกอบได้อย่างสมบูรณ์แบบ ดังนั้น การทดสอบในกระบวนการ BDD สามารถใช้เป็นตัวแทนอย่างเป็นทางการของงาน ( เรื่องราวของผู้ใช้) ในแง่ การต่อสู้ซึ่งช่วยให้คุณประหยัดเวลาในการเขียนข้อกำหนดทางเทคนิคและเอกสารสำหรับผลิตภัณฑ์สำเร็จรูป

กรอบการทดสอบหน่วย JavaScript ควรเป็นอย่างไร

หน่วย JavaScript ที่สมบูรณ์และเครื่องมือทดสอบการรวมควรประกอบด้วยส่วนประกอบต่อไปนี้:

  • ไลบรารีการยืนยัน (ชุดวิธีการตรวจสอบสถานะของส่วนประกอบเมื่อสิ้นสุดการทดสอบแต่ละครั้ง)
  • ห้องสมุดจำลอง (เครื่องมือสำหรับสร้างวัตถุจำลองและ "นักเรียน" อื่น ๆ );
  • นักวิ่งทดสอบ (เครื่องมือ เริ่มต้นอัตโนมัติทดสอบโดยรองรับเบราว์เซอร์ส่วนใหญ่ รวมถึงเบราว์เซอร์ iOS และ Android)
  • บล็อกการเชื่อมต่อกับระบบยอดนิยมของการรวมระบบอย่างต่อเนื่อง (Continuous Integration)

กลยุทธ์การทดสอบหน่วย JavaScript

ปัจจุบัน มีสามกลยุทธ์สำหรับการทดสอบหน่วยโค้ด JavaScript (สำหรับรายละเอียดเพิ่มเติม โปรดดูบทที่สามของหนังสือ Test-Driven JavaScript Development ของ Christian Johansen):

  • ในเบราว์เซอร์การทดสอบ;
  • หัวขาดการทดสอบ;
  • การทดสอบไปพร้อมกัน JsTestDriver.

การทดสอบในเบราว์เซอร์เกี่ยวข้องกับการเรียกใช้หน่วยทั้งหมดและการทดสอบการรวมระบบจากหน้า HTML ที่ผู้พัฒนาเปิดในเบราว์เซอร์ที่ต้องการด้วยตัวเอง วิธีการนี้ง่ายและไม่ซับซ้อน อย่างไรก็ตาม ข้อเสียของมันคือไม่ได้ให้ความเป็นไปได้ในการรวมการทดสอบดังกล่าวในการบูรณาการอย่างต่อเนื่อง นอกจากนี้ การเปิดหน้า HTML ด้วยตนเองในเบราว์เซอร์ตั้งแต่ 10 ตัวขึ้นไปและการกด "F5" อย่างต่อเนื่องอาจเป็นเรื่องที่น่าเบื่อสำหรับนักพัฒนา

การทดสอบแบบไม่มีส่วนหัวหมายถึงการทดสอบโค้ด JavaScript ทั้งหมดบนโปรแกรมจำลอง ซึ่งสามารถเขียนได้ด้วย Java, Ruby, JavaScript, C++ เป็นต้น โปรแกรมจำลองที่มีชื่อเสียงที่สุดคือ PhantomJS ซึ่งเป็นไฟล์ เว็บคิต,เปิดตัวตั้งแต่ บรรทัดคำสั่ง. ในข้อดีของอีมูเลเตอร์นั้นสามารถสังเกตได้ว่าสามารถใช้ในการรวมอย่างต่อเนื่องได้อย่างง่ายดายและยังช่วยให้คุณสามารถเปิดการทดสอบทั้งหมดโดยอัตโนมัติจากบรรทัดคำสั่ง อย่างไรก็ตาม วิธีการนี้มีข้อเสียเปรียบอย่างมาก - โค้ดไม่ได้รับการทดสอบบนเบราว์เซอร์จริง ดังนั้นจึงมีความเสี่ยงที่จะไม่พบข้อผิดพลาดของเบราว์เซอร์ที่ไม่ได้เกิดขึ้นซ้ำในโปรแกรมจำลอง ก่อนการมาถึงของ JsTestDriver คุณมักจะเห็นการทดสอบในเบราว์เซอร์รวมกับการทดสอบแบบ Headless เนื่องจากทั้งสองส่วนเสริมซึ่งกันและกันได้เป็นอย่างดี

การทดสอบเป็นส่วนสำคัญของวงจรการพัฒนาซอฟต์แวร์ ทีมพัฒนามือใหม่มักประเมินบทบาทต่ำเกินไปและตรวจสอบประสิทธิภาพของแอปพลิเคชันด้วยวิธีแบบเก่า นั่นคือ "ใช้งานได้ และไม่เป็นไร" ไม่ช้าก็เร็ว กลยุทธ์นี้จะล้มเหลวและตัวติดตามบั๊กก็เริ่มครอบงำกองทัพของงานจำนวนนับไม่ถ้วน เพื่อไม่ให้ตกหลุมพรางดังกล่าว ฉันขอแนะนำทุกครั้งให้จัดการกับความแตกต่างของการทดสอบโค้ด JavaScript

JavaScript ไม่ใช่เค้กอีกต่อไป!

ฉันเดาว่าฉันไม่จำเป็นต้องอธิบายให้คุณฟังว่าทุกวันนี้ JavaScript ไม่ใช่แค่ภาษาที่ช่วยเพิ่มสีสัน รูปร่างแอพพลิเคชั่น. แต่อย่างไรก็ตาม ฉันจะอธิบายและแนะนำตัวเล็กน้อย เพราะฉันจะได้รับเงินมากขึ้น เงินมากขึ้น! 🙂 ดังนั้น เวลาที่ใช้ JavaScript เพื่อล้อเล่นหรือสร้างเมนูจึงหมดไปตลอดกาล ตอนนี้เป็นภาษาอิสระที่ทำงานได้ดีทั้งบนไคลเอ็นต์และเซิร์ฟเวอร์ บทบาทของ JavaScript เพิ่มขึ้นอย่างมาก ซึ่งหมายความว่าเมื่อเขียนโค้ด คุณไม่ควรอายที่จะใช้แนวปฏิบัติที่ได้รับการพิสูจน์แล้วในภาษาการเขียนโปรแกรมอื่นๆ

ฉันหมายถึงอะไรโดยการปฏิบัติและกระบวนทัศน์? แน่นอนรูปแบบสถาปัตยกรรม MVC (ตัวควบคุมมุมมองแบบจำลอง) และรูปแบบการจัดระเบียบรหัส เมื่อทำตามเคล็ดลับง่ายๆ เหล่านี้ คุณจะสามารถเขียนโค้ดได้ดีขึ้น ซึ่งนอกจากจะดูแลรักษาง่ายแล้ว ยังมีความสามารถในการทดสอบโดยอัตโนมัติอีกด้วย

กฎสำหรับการทดสอบที่ดี

  • การทดสอบควรง่ายที่สุด ยิ่งข้อสอบยากเท่าไหร่ก็ยิ่งมีโอกาสผิดพลาดมากขึ้นเท่านั้น
  • การทดสอบควรจัดกลุ่มเป็นโมดูลเพื่อให้ง่ายต่อการค้นหาจุดบกพร่องและสามารถทดสอบส่วนเฉพาะของแอปพลิเคชันได้ในภายหลัง
  • การทดสอบแต่ละครั้งไม่ควรขึ้นอยู่กับการทดสอบอื่น
  • ควรเขียนการทดสอบแยกต่างหากทุกครั้งที่คุณพบจุดบกพร่อง

ข้อผิดพลาดของผู้ทดสอบส่วนใหญ่

ไม่มีความลับใดที่วิธีการทดสอบที่ได้รับความนิยมมากที่สุดคือการทดสอบสายตาซ้ำซาก สาระสำคัญของมันคือความอัปยศอดสู - ฉันเขียนโค้ดสองสามพันบรรทัดแก้ปัญหาและเปิดตัวการสร้างของฉัน ฉันเล่นคลิก - ทุกอย่างดูเหมือนจะใช้งานได้คุณสามารถอัปโหลดไปยังเซิร์ฟเวอร์การต่อสู้ ทุกอย่างง่ายมากและด้วยความใส่ใจของนักพัฒนา (ตามหลักการแล้วแต่ละคนมีชื่อเล่นว่า "ผู้ทดสอบ") คุณสามารถพึ่งพาการทำงานที่ถูกต้องของแอปพลิเคชันได้

ในทางปฏิบัติทุกอย่างแตกต่างกันเล็กน้อย ตามกฎแล้วไม่มีผู้ทดสอบแยกต่างหาก ผู้พัฒนาเองพยายามตรวจสอบความสามารถในการทำงานของโปรแกรมโดยดำเนินการตามลำดับของการกระทำที่ระบุในงานด้านเทคนิค รหัสขั้นสูงกว่าจะสร้างการทดสอบการผสานรวมประเภทนี้โดยอัตโนมัติด้วยเครื่องมืออย่าง Selenium

ดังนั้นโปรแกรมเมอร์จึงมีโอกาสตรวจจับเฉพาะข้อผิดพลาดที่ร้ายแรงที่สุดเท่านั้น น่าเสียดายที่การกระทำของผู้ใช้ "งี่เง่า" และ "คาดไม่ถึง" รวมถึงการเคลื่อนไหวที่ยุ่งยากในตรรกะทางธุรกิจใน 99% ของกรณียังคงอยู่เบื้องหลัง

การมีเครื่องทดสอบแยกต่างหากยังช่วยแก้ปัญหาได้บางส่วนและจนถึงเวลาที่กำหนด แม้ว่าเราจะละทิ้งความใส่ใจในรายละเอียดของเขา คุณภาพของการทดสอบของเขาก็จะมีแนวโน้มเป็นศูนย์เมื่อแอปพลิเคชันเติบโตขึ้น ฉันจะยกตัวอย่างจากการปฏิบัติ

เมื่อฉันได้รับมอบหมายให้พัฒนาโปรแกรมเล็กๆ ในแง่ของการทำงาน โครงการคล้ายกับ CRM ที่ง่ายที่สุด ซึ่งฉันนำมาใช้ในเวลาที่สั้นที่สุด เมื่อได้รับค่าตอบแทนครบกำหนดแล้ว ฉันจึงมอบแหล่งที่มาทั้งหมดให้กับลูกค้าและลืมเกี่ยวกับโครงการเป็นเวลาแปดเดือน จากนั้นสิ่งที่น่าสนใจที่สุดก็เริ่มขึ้น ลูกค้าตัดสินใจที่จะขยายการทำงานของโปรแกรมอย่างจริงจังและโทรหาฉันเพื่อขอความช่วยเหลือ แน่นอน ฉันรับมันมาและเริ่มแกะสลักฟังก์ชันแล้วฟังก์ชันเล่า... ในตอนแรกมันไม่ใช่เรื่องยาก แต่เมื่อพูดถึงการรวมฟังก์ชันการทำงานโดยรวม ฝูงแมลงที่ส่งเสียงพึมพำก็พุ่งเข้ามาหาฉัน โค้ดบางส่วนเริ่มขัดแย้งกัน และฉันต้องใช้เวลามากในการแก้ไขความขัดแย้ง “คุณไม่เห็นว่ามีปัญหากับใบสมัครของคุณได้อย่างไร” ผู้อ่านจะถาม ฉันจะตอบว่า: ฉันเปิดตัวแล้ว แต่เนื่องจากแอปพลิเคชันเติบโตขึ้น ฉันจึงไม่มีเวลาและความกังวลใจที่จะทดสอบฟังก์ชันการทำงานทั้งหมดโดยรวม ฉันจำกัดตัวเองให้ทดสอบเฉพาะฟังก์ชันแต่ละฟังก์ชันและจ่ายเงินอย่างไม่เห็นแก่ตัว คุณธรรมของเรื่องราว: "คิดว่าการทดสอบเป็นส่วนสำคัญของการพัฒนา"

การทดสอบหน่วยเป็นเหมือนกระสุนเงิน

การทดสอบหน่วยเป็นวิธีที่ดีที่สุดในการไม่ต้องกังวลและเพิ่มการรับประกันว่าแต่ละส่วนของแอปพลิเคชันของคุณจะใช้งานได้ หากคุณไม่เคยพบสัตว์ร้ายตัวนี้ ฉันจะอธิบายสั้น ๆ การทดสอบหน่วยช่วยให้คุณทำกระบวนการทดสอบโดยอัตโนมัติและทดสอบคุณสมบัติแต่ละอย่างของแอปพลิเคชันของคุณ

หลังจากเสร็จสิ้นการพัฒนา คุณลักษณะใหม่(เป็นไปได้ที่จะเขียนการทดสอบก่อนเริ่มการพัฒนา) นักพัฒนาเขียนรหัสพิเศษเพื่อทดสอบรหัสของเขา จำเป็นต้องจำลองสถานการณ์ต่าง ๆ และส่งคืนค่า เช่น เราเขียนฟังก์ชันเพื่อตัดช่องว่าง (trim) ในการทดสอบประสิทธิภาพ เราต้องเตรียมการทดสอบหลายอย่างที่จะช่วยให้เราสามารถยืนยันได้ว่า:

  • เมื่อผ่านสตริง "string" เราจะได้รับ "string" เป็นเอาต์พุต
  • เมื่อผ่านเงื่อนไข "บรรทัดที่ 9" ที่เอาต์พุต เราจะได้ "บรรทัดที่ 9"

เรายังสามารถเพิ่มการทดสอบสำหรับพารามิเตอร์อินพุตอื่นๆ (เช่น แทนที่อักขระเว้นวรรคด้วยแท็บ) โดยทั่วไป ยิ่งเราครอบคลุมโค้ดได้ดียิ่งขึ้นด้วยการทดสอบ และยิ่งเราคาดการณ์ถึงตัวเลือกเชิงลบที่เป็นไปได้มากเท่าไร โอกาสที่ในช่วงเวลาที่สำคัญที่สุดจะมีผมเส้นเล็กๆ อยู่บนศีรษะก็จะยิ่งสูงขึ้นเท่านั้น

ในโลกของ JS การทดสอบมักจะเขียนขึ้นโดยใช้เฟรมเวิร์กเฉพาะ พวกเขามีทุกสิ่งที่คุณต้องการ เช่นเดียวกับเครื่องมือบางอย่างสำหรับจัดระเบียบรายงานความคืบหน้าการทดสอบ

Tests!= รหัสพิเศษ

ผู้ทดสอบที่ไม่ใช่หน่วยชอบโต้แย้งว่าการทดสอบหน่วยจำเป็นต้องเขียนและบำรุงรักษา รหัสเพิ่มเติม. พวกเขากล่าวว่ากำหนดเวลาในโครงการจริงมักถูกบีบอัดและไม่สามารถเขียนโค้ดเพิ่มเติมได้

เมื่อไม่มีเวลาสอบ

ในกรณีที่ไม่มีเวลา การเขียนการทดสอบสำหรับฟังก์ชันง่าย ๆ (ใช้การตัดแต่งเดียวกัน () จากตัวอย่างในบทความ) นั้นไม่มีเหตุผลที่จะดีกว่าหากมุ่งเน้นไปที่ส่วนที่สำคัญที่สุดของโค้ด ควรปฏิบัติตามกฎเดียวกันเมื่อเขียนโค้ดที่เปลี่ยนแปลงบ่อย ข้อกำหนดในการอ้างอิงของโครงการที่ใช้งานจริงมักจะเปลี่ยนแปลง และคุณสมบัติบางอย่างต้องได้รับการปรับปรุงอย่างต่อเนื่อง การเปลี่ยนแปลงดังกล่าวอาจนำไปสู่ช่วงเวลาที่ไม่พึงประสงค์ - รหัสที่เปลี่ยนแปลงนั้นทำงานได้ดีกับข้อมูลใหม่ แต่จะไม่ย่อยข้อมูลเก่า เพื่อไม่ให้เกิดข้อผิดพลาดที่นี่ควรตรวจสอบฟังก์ชั่นดังกล่าวทันที จำกฎง่ายๆ: ไม่มีเวลาครอบคลุมโค้ดทั้งหมดด้วยการทดสอบ - ครอบคลุมส่วนที่สำคัญที่สุด


สำหรับกำหนดเวลาที่รัดกุม ฉันเห็นด้วย แต่ฉันพร้อมที่จะโต้แย้งเกี่ยวกับส่วนของรหัสพิเศษ ในแง่หนึ่งใช่ - การทดสอบต้องการรหัสเพิ่มเติมและด้วยเหตุนี้จึงถึงเวลาที่ต้องเขียน ในทางกลับกัน รหัสนี้มีบทบาทเป็นถุงลมนิรภัยในรถยนต์ และจะคุ้มค่าอย่างแน่นอนเมื่อแอปพลิเคชันเติบโตขึ้น
  • Cristian Johansen Test-Driven JavaScript Development (goo.gl/mE6Is) เป็นหนึ่งในหนังสือไม่กี่เล่มที่ดู JavaScript จากมุมมองของการทดสอบการเขียน
  • John Resing, Beer Bibo JavaScript Ninja Secrets (goo.gl/xquDkJ) เป็นหนังสือที่ดีที่จะเป็นประโยชน์สำหรับนักพัฒนา JS ระดับกลางเป็นหลัก หนังสือเล่มนี้กล่าวถึงรายละเอียดเกี่ยวกับปัญหาของการเขียนโค้ดข้ามเบราว์เซอร์ที่มีประสิทธิภาพ ความแตกต่างของการจัดการเหตุการณ์ และอื่นๆ อีกมากมาย
  • เดวิด ฟลานาแกน JavaScript. คู่มือฉบับสมบูรณ์» (goo.gl/rZjjk) - หนังสือเล่มนี้ได้รับการพิมพ์ซ้ำถึง 6 ครั้ง และแต่ละรุ่นก็เป็นหนังสือขายดี แท้จริงแล้วเป็นที่สุด คู่มือโดยละเอียดบน JavaScript ซึ่งผู้พัฒนา JS ทุกคนต้องอ่านอย่างน้อยหนึ่งครั้ง
  • PhantomJS + JSCoverage + QUnit หรือการทดสอบหน่วยคอนโซล JS พร้อมการคำนวณความครอบคลุม (goo.gl/FyQ38) - ผู้เขียนบทความสาธิตการใช้ชุดแพ็คเกจด้านบนเพื่อรวบรวมสถิติและคำนวณเปอร์เซ็นต์ความครอบคลุมของโค้ดโดยการทดสอบ
  • กรณีการใช้งาน PhantomJS ที่มีประโยชน์ - หน้านี้แสดงการใช้งานการต่อสู้ PhantomJS จำนวนมาก

เมื่อไม่มีเวลาและความปรารถนาที่จะปฏิเสธการทดสอบการเขียนเป็นสิ่งที่ทรมาน ให้คิดสามครั้ง บางที ในกรณีนี้ การทดสอบจะครอบคลุมเฉพาะส่วนที่ยุ่งยากที่สุดของโค้ด แทนที่จะละทิ้งการทดสอบโดยสิ้นเชิง คิดอยู่เสมอเพื่ออนาคตราวกับว่าในหนึ่งเดือนโปรแกรมของคุณอาจเติบโตเป็นขนาดที่ไม่เคยมีมาก่อน

ไม่ได้ทดสอบรหัสทั้งหมด

ทำไมฉันถึงบอกว่าคุณต้องคิดเกี่ยวกับการทดสอบก่อนที่จะเขียนรหัสหลัก? ใช่ เนื่องจากรหัสที่ควรจะครอบคลุมในการทดสอบหน่วยในขั้นต้นนั้นเขียนในรูปแบบที่แตกต่างออกไปเล็กน้อย ไม่สามารถทดสอบรหัสทั้งหมดได้ โค้ดที่ผสมระหว่างตรรกะและการแทนค่า และแม้กระทั่งฉันไม่เข้าใจตรงไหน ก็ไม่สามารถทดสอบได้ตามปกติ ที่นี่ฉันมักจะแนะนำให้คุณปฏิบัติตามกฎง่ายๆ:

  • ไม่ต้องเขียนฟังก์ชันใหญ่โต แต่ละฟังก์ชันควรแก้ปัญหาเดียว ไม่ใช่ 100500 สถานการณ์ที่เป็นไปได้ ตัวอย่างเช่น คุณไม่จำเป็นต้องวางโค้ดสำหรับการส่งข้อมูลไปยังเซิร์ฟเวอร์ในฟังก์ชันที่รับผิดชอบในการเตรียมข้อมูลเหล่านั้น
  • ฟังก์ชันที่มีโค้ดมากกว่า 10 บรรทัดน่าจะเป็นฟังก์ชันที่ไม่ดี
  • ตรรกะและการนำเสนอไม่ควรไปด้วยกัน

QUnit - คลาสสิกของประเภทจากผู้สร้าง jQuery

QUnit เป็นที่นิยมในหมู่นักพัฒนา JavaScript โดยเฉพาะ อย่างแรก มีการบันทึกไว้อย่างดีและใช้งานง่าย อย่างที่สอง สร้างโดยผู้เขียน jQuery ไลบรารีนี้เหมาะสำหรับการทดสอบทั้งโค้ด JavaScript ที่ใช้ jQuery และเนทีฟ


ดาวน์โหลด รุ่นล่าสุด QUnit คุณสามารถจากเว็บไซต์อย่างเป็นทางการ ไลบรารีมาในรูปแบบไฟล์ JS และ CSS ไฟล์เดียว สมมติว่าคุณทราบวิธีการโหลดส่วนประกอบที่จำเป็น และถ้าเป็นเช่นนั้น ก็ถึงเวลาเขียนแบบทดสอบทดลอง อย่าเพิ่งไปไกลและลองทดสอบฟังก์ชั่น trim()

เพื่อสาธิตการทดสอบ ฉันได้สร้างโครงการอย่างง่ายโดยมีโครงสร้างดังต่อไปนี้:

  • index.html - ไฟล์หลักที่จะแสดงผลการทดสอบ
  • qunit-1.12.0.js - ไฟล์ไลบรารี QUnit
  • example.js - ไฟล์ที่มีรหัสสำหรับการทดสอบ (ในกรณีของเรา คำอธิบายของฟังก์ชัน trim());
  • test.js - ไฟล์พร้อมการทดสอบ
  • qunit-1.12.0.css - รูปแบบสำหรับการออกแบบรายงานพร้อมการทดสอบ

เนื้อหาของไฟล์ index.html และ test.js แสดงอยู่ในรายการที่ 1 และ 2 รายการที่สองที่เราสนใจมากที่สุดคือการประกาศฟังก์ชันภายใต้การทดสอบ (trim()) และรหัสทดสอบเพื่อตรวจสอบว่ามันใช้งานได้ . โปรดทราบว่าฟังก์ชัน trim() สามารถอยู่ที่ใดก็ได้ ฉันใส่ไว้ในรายการที่สองเพื่อประหยัดพื้นที่ในบันทึก
ทีนี้มาดูการทดสอบกัน ไลบรารี QUnit.js มีวิธีการมากมาย:

  • ทดสอบ () - เสื้อคลุมสำหรับคำอธิบายการทดสอบ
  • ok() - การยืนยันให้คุณตรวจสอบความจริงของพารามิเตอร์ตัวแรก ในตัวอย่างของเรา ฉันส่งการเรียกไปยังฟังก์ชัน trim() ที่เรากำหนดไว้และเปรียบเทียบกับค่าที่ฉันคาดว่าจะได้รับ หากเงื่อนไขเป็นจริง แสดงว่าผ่านการทดสอบ
  • เท่ากับ() - วิธีนี้ช่วยให้คุณตรวจสอบความเท่าเทียมกันของพารามิเตอร์ตัวแรกและตัวที่สอง ให้สังเกตทันทีว่า วิธีนี้ทำการตรวจสอบแบบไม่เข้มงวด ดังนั้นจึงเหมาะสำหรับสเกลาร์เท่านั้น
  • notEqual() ตรงข้ามกับเท่ากับ() ดำเนินการหากค่าแรกไม่เท่ากับค่าที่สอง
  • เข้มงวดEqual() - คล้ายกับเท่ากับ () โดยมีข้อแตกต่าง - ใช้การตรวจสอบอย่างเข้มงวด (นั่นคือตรวจสอบประเภทข้อมูลด้วย)
  • notStrictEqual() - ตรงกันข้ามกับ maximumEqual();
  • deepEqual() - เมธอดสำหรับ recursive statement, ใช้สำหรับ primitives, arrays, object;
  • notDeepEqual() - ตรงข้ามกับ deepEqual();
  • Raises() เป็นการยืนยันสำหรับการทดสอบฟังก์ชันการเรียกกลับที่มีข้อยกเว้น

ในรายการที่สอง ฉันได้แสดงให้เห็นอย่างชัดเจนถึงวิธีการนำวิธีการเหล่านี้ไปปฏิบัติจริง หากคุณเรียกใช้กรณีทดสอบในแบบฟอร์มนี้ การทดสอบทั้งหมดจะผ่านสำเร็จ (ดูรูปที่เกี่ยวข้อง) เพื่อให้เห็นความแตกต่างระหว่างการทดสอบที่ผ่านและการทดสอบที่ไม่ผ่าน ฉันได้เปลี่ยนรหัสของการทดสอบหนึ่งเล็กน้อย ฉันจงใจเพิ่มผลลัพธ์ที่ผิดพลาดลงในบรรทัดด้วยการทดสอบโดยใช้trictEqual() (ดูรูปที่เกี่ยวข้อง)

รายการ 1. เนื้อหาของไฟล์ index.html การทดสอบด้วย QUnit



ด้วยการทดสอบฟังก์ชั่นง่ายๆ ดูเหมือนว่าจะเข้าใจ ไม่ว่าในกรณีใด ฉันไม่มีอะไรจะเพิ่มเติม จากนั้นคุณจะต้องใช้รหัสจริงและลองเขียนการทดสอบด้วยตัวเอง มาดูงานอื่นที่พบบ่อยสำหรับนักพัฒนา JavaScript นั่นคือการทดสอบฟังก์ชันอะซิงโครนัส แอปพลิเคชันที่เต็มไปด้วยรหัส JavaScript โต้ตอบ 99% กับฝั่งเซิร์ฟเวอร์โดยใช้ AJAX เป็นไปไม่ได้ที่จะทิ้งโค้ดนี้ไว้โดยไม่ทดสอบ แต่การทดสอบการเขียนจะดูแตกต่างออกไปเล็กน้อย พิจารณาตัวอย่าง:

AsyncTest("myAsyncFunc()", function () ( setTimeout(function () ( ok(myAsyncFunc() == จริง, "ข้อมูลผ่านสำเร็จ"); start(); ), 500); ));

ข้อแตกต่างหลักระหว่างตัวอย่างนี้กับตัวอย่างก่อนหน้าคือใช้ asyncTest() แทน test() wrapper ดังนั้นจึงระบุโดยตรงว่าฉันสนใจการทดสอบแบบอะซิงโครนัส ต่อไป ฉันเริ่มหมดเวลา 500 มิลลิวินาที ในช่วงเวลานี้ ฟังก์ชัน myAsyncFunc() ควรถ่ายโอนข้อมูลไปยังเซิร์ฟเวอร์ทดสอบ และถ้าทุกอย่างเรียบร้อยดี ให้ส่งคืนค่าจริง มาถึงช่วงเวลาที่น่าสนใจที่สุด เมื่อมีการเรียกใช้ asyncTest() เธรดของการดำเนินการจะหยุดทำงาน และเมื่อการทดสอบเสร็จสิ้น จะต้องเริ่มด้วยตัวมันเอง เพื่อควบคุมการไหลของการดำเนินการ QUnit มีเมธอด start() และ stop()


การทดสอบฟังก์ชันแบบอะซิงโครนัสด้วยไลบรารี QUnit นั้นค่อนข้างตรงไปตรงมา ตัวอย่างสุดท้ายที่ฉันต้องการจะดูคือการเขียนการทดสอบที่ทำการตรวจสอบแบบอะซิงโครนัสหลายรายการ คำถามหลักที่เกิดขึ้นในงานดังกล่าวคือตำแหน่งที่เหมาะสมที่สุดในการเริ่มเธรดการดำเนินการ เอกสารอย่างเป็นทางการแนะนำให้ใช้สิ่งที่ต้องการ

AsyncTest("myAsyncFunc()", function () ( คาดว่า(3); // ทำการทดสอบสามครั้งที่นี่ ok(myAsyncFunc(), "ทำให้โลกดีขึ้น 1"); ตกลง(myAsyncFunc(), "ทำให้โลกดีขึ้น 2 ") ; ok(myAsyncFunc(), "ทำให้โลกนี้น่าอยู่ขึ้น 3"); setTimeout(function () ( start(); ), 3000); ));

ทดสอบการกระทำที่กำหนดเอง

คุณควรจำไว้เสมอว่าอินเทอร์เฟซทุกประเภทเขียนด้วย JavaScript ตัวอย่างเช่น ผู้ใช้คลิกที่แมงดาและบางสิ่งควรเกิดขึ้นตามการคลิกของเขา มีโค้ด "ส่วนต่อประสาน" จำนวนมากในโครงการและจำเป็นต้องมีการทดสอบด้วย มาดูกันว่าเราจะจำลองการกดแป้นพิมพ์ของผู้ใช้และเขียนการทดสอบแยกต่างหากสำหรับการกระทำนี้ได้อย่างไร ลองนึกดูว่าเรามีฟังก์ชันบางอย่างที่บันทึกการกดแป้นต่างๆ ฉันให้รหัสกับเธอในรายการที่สาม

รายการ 3. การบันทึกการกดแป้นพิมพ์ ฟังก์ชัน KeyLogger(เป้าหมาย) ( if (!(อินสแตนซ์นี้ของ KeyLogger)) ( ส่งคืน KeyLogger ใหม่(เป้าหมาย); ) this.target = target; this.log = ; var self = this; this.target.off ("คีย์ดาวน์").บน("คีย์ดาวน์", ฟังก์ชัน(เหตุการณ์) ( self.log.push(event.keyCode); )); )

ทีนี้มาลองทดสอบฟังก์ชั่นนี้กัน ก่อนอื่น ในเนื้อหาของการทดสอบ เราต้องเลียนแบบแป้นที่กด วิธีที่ง่ายที่สุดในการทำเช่นนี้คือใช้ไลบรารี jQuery ซึ่งช่วยให้คุณสร้างเหตุการณ์ในโค้ดสองสามบรรทัด (ดูรายการ 4)

รายการ 4. รหัสทดสอบสำหรับการทดสอบ KeyLogger("การทดสอบการบันทึกคีย์", ฟังก์ชัน () ( var เหตุการณ์, $doc = $(เอกสาร), คีย์ = KeyLogger($doc); เหตุการณ์ = $.เหตุการณ์("คีย์ดาวน์"); เหตุการณ์ .keyCode = 9; $doc.trigger(event); equal(keys.log.length, 1, "บันทึกคีย์"); เท่ากับ(keys.log, 9, "คีย์ที่กดด้วยรหัส 9 ถูกบันทึก"); ));

ในตอนต้นของรายการพร้อมการทดสอบ ฉันเตรียมกิจกรรมเพื่อจำลองการกดแป้น - "การกดแป้นพิมพ์" เราจะสนใจที่จะกดแป้น Tab (รหัส 9) จากนั้นใช้เมธอด trigger() ฉันส่งเหตุการณ์ที่เตรียมไว้ หลังจากนั้นฉันสามารถเริ่มการทดสอบได้ ขั้นแรก เราตรวจสอบภาพรวม - มีการกดคีย์หรือไม่ จากนั้นตามด้วยรหัส

DOM ภายใต้หน้ากากของการทดสอบ

เนื่องจาก Qunit.js อนุญาตให้คุณทดสอบการดำเนินการที่กำหนดเองได้ การทดสอบการเขียนสำหรับ DOM จึงไม่น่ามีปัญหาเช่นกัน นี่เป็นเรื่องจริง และตัวอย่างด้านล่างจะยืนยันคำพูดของฉัน ฉันจะไม่แสดงความคิดเห็น เพียงแค่ดูรหัสแล้วทุกอย่างจะชัดเจน:

Test("การเพิ่มองค์ประกอบ div ใหม่", function () ( var $fixture = $("#qunit-fixture"); $fixture.append("

นี่คือ div ใหม่
"); equal($("div", $fixture).length, 1, "เพิ่ม div ใหม่เรียบร้อยแล้ว!"); ));

PhantomJS - เรียกใช้การทดสอบจากคอนโซล


การทดสอบการเขียนโดยใช้ไลบรารี QUnit.js นั้นสะดวกและง่ายดาย แต่ไม่ช้าก็เร็ว ความต้องการของคุณจะทำให้การเรียกใช้ การทดสอบ และการรวบรวมผลลัพธ์เป็นแบบอัตโนมัติ ตัวอย่างเช่น ฉันมีเครื่องเสมือนแยกต่างหากใน DigitalOcean สำหรับธุรกิจนี้ ซึ่งฉันจัดการได้โดยใช้คอนโซลเท่านั้น

โครงการ PhantomJS แก้ปัญหานี้ได้อย่างดีพอ นี่ไม่ใช่แค่เฟรมเวิร์กอื่นสำหรับการเขียนการทดสอบหน่วย แต่เป็นเวอร์ชันคอนโซลเต็มรูปแบบของเอ็นจิ้น WebKit พูดง่ายๆ ก็คือ แอปพลิเคชันนี้เลียนแบบเบราว์เซอร์ ด้วยความช่วยเหลือของ PhantomJS มันไม่ได้เป็นเพียงการยืนยันการดำเนินการทดสอบโดยอัตโนมัติ แต่ยังแก้ปัญหางานจำนวนมากที่เกิดขึ้นไม่ช้าก็เร็วต่อหน้านักพัฒนา: รับผลลัพธ์ของการแสดงหน้าเป็นไฟล์ (PNG, JPG) ฟังก์ชันการตรวจสอบเครือข่าย (ความเร็วในการโหลด ประสิทธิภาพโดยรวม ฯลฯ) การจำลองการกระทำของผู้ใช้ และอื่นๆ ฉันแนะนำว่าอย่าขี้เกียจและอ่านเอกสารอย่างเป็นทางการของโครงการนี้คุณจะพบสิ่งที่น่าสนใจสำหรับตัวคุณเองอย่างแน่นอน

PhantomJS สามารถคอมไพล์สำหรับแพลตฟอร์มต่างๆ (*nix, OS X, Windows) หากคุณพัฒนาทุกอย่างภายใต้ Windows ก็ไม่มีปัญหา - รวมไบนารีแล้วดำเนินการต่อ ปัญหาเล็กน้อยในการเปิดใช้งานอาจเกิดขึ้นได้หากคุณติดตั้งอะแดปเตอร์วิดีโอสองตัว หนึ่งในนั้นคือ NVIDIA ในกรณีนี้ คุณจะต้องใช้แฮ็คที่อธิบายไว้ในแถบด้านข้าง


ลองทำความคุ้นเคยกับ PhantomJS ในทางปฏิบัติ ในการเรียกใช้การทดสอบที่เตรียมไว้ในส่วนสุดท้ายผ่าน PhantomJS และรับผลลัพธ์ของการดำเนินการในคอนโซล เราจำเป็นต้องมีสคริปต์ตัวโหลดพิเศษ - run-qunit.js เปิดคอนโซล (ฉันทำงานบน Windows ดังนั้นฉันจึงใช้ cmd) และพิมพ์คำสั่งในรูปแบบ

phantom.exe<путь к run-qunit.js> <путь к странице с тестами>

ในกรณีของฉัน คำสั่งเรียกใช้กลายเป็นดังนี้:

E:\soft\phantomjs>phantomjs.exe E:\temp\testjsforx\qunit\run-qunit.js ไฟล์:///E: /temp/testjsforx/qunit/index.html

ผลลัพธ์ของการดำเนินการ:

การทดสอบเสร็จสิ้นในเวลา 2592 มิลลิวินาที ยืนยัน 9 จาก 9 ผ่าน 0 ล้มเหลว

ผ่านการทดสอบทั้งหมด

จำเป็นอย่างยิ่งที่จะต้องครอบคลุมโค้ดด้วยการทดสอบ และไม่สำคัญว่าคุณจะสร้างแอปพลิเคชันในระดับใด ฉันเตือนคุณอีกครั้ง: แม้แต่โปรแกรมที่เล็กที่สุดก็กลายเป็นสัตว์ประหลาดที่เงอะงะซึ่งจำเป็นต้องได้รับการสนับสนุนและสมบูรณ์ด้วยฟังก์ชันการทำงาน โค้ดที่ผ่านการทดสอบอย่างดีคือกุญแจสู่ความสำเร็จและคุณภาพ ใช่ มันไม่ง่ายเลยที่จะเริ่มเขียนโค้ดที่เหมาะกับการทดสอบอัตโนมัติในทันที แต่เชื่อฉันเถอะ ความทรมานทั้งหมดนี้จะมากกว่าการชำระคืนในอนาคต นั่นคือทั้งหมดสำหรับวันนี้ โชคดี!

ปัญหา PhantomJS บน Windows

มันเพิ่งเกิดขึ้น แต่ฉันทดสอบตัวอย่างทั้งหมดสำหรับบทความนี้ไม่ใช่บน Linux แต่ใช้ Windows 7 รุ่นเก่าที่ดี ปรากฎว่า PhantomJS มีปัญหาเมื่อทำงานบนระบบที่ใช้อะแดปเตอร์วิดีโอหลายตัว บนแล็ปท็อปของฉันนอกเหนือจากชิปวิดีโอในตัวแล้ว NVIDIA ยังแฮงเอาท์และด้วยเหตุนี้ PhantomJS จึงปฏิเสธที่จะตอบสนองต่อคำสั่ง phantom.exit () อย่างเด็ดขาด ผลที่ตามมาก็คือ หลังจากเรียกใช้สคริปต์แล้ว กระบวนการ PhantomJS ก็ยังไม่สิ้นสุดการทำงานและค้างอยู่ในหน่วยความจำต่อไป หน้าต่างเทอร์มินัลหยุดตอบสนองต่อคำสั่งออก ( ไม่ได้ช่วย)

หากคุณประสบปัญหาที่คล้ายกันและกำลังวางแผนที่จะใช้ PhantomJS บน Windows ให้เตรียมพร้อมที่จะทำการแฮ็กต่อไปนี้ แผงเปิด การควบคุมของ NVIDIA. ค้นหารายการ "การตั้งค่า 3D" ในแผนภูมิ ทางด้านขวา ตัวเลือก "ที่ต้องการ อะแดปเตอร์กราฟิก". โดยค่าเริ่มต้น. ค่าของมันถูกตั้งค่าเป็นการเลือกอัตโนมัติ เราจำเป็นต้องเปลี่ยนเป็น "โปรเซสเซอร์ NVIDIA ประสิทธิภาพสูง" หรือ "ฮาร์ดแวร์กราฟิกรวม" หลังจากเคล็ดลับง่ายๆ นี้ PhantomJS ก็เริ่มประพฤติตนอย่างเชื่อฟัง

การสร้างกรณีทดสอบที่มีประสิทธิภาพเป็นสิ่งสำคัญ โครงการที่สำคัญในกรณีที่ลักษณะการทำงานของส่วนต่างๆ ของแอปพลิเคชันอาจเปลี่ยนแปลงได้จากหลายสาเหตุ บางทีปัญหาที่พบบ่อยที่สุดคือเมื่อนักพัฒนากลุ่มใหญ่กำลังทำงานในโมดูลเดียวกันหรือที่เกี่ยวข้องกัน สิ่งนี้สามารถนำไปสู่การเปลี่ยนแปลงโดยไม่ได้วางแผนในการทำงานของฟังก์ชันที่เขียนโดยโปรแกรมเมอร์คนอื่นๆ หรือการทำงานภายใต้กำหนดเวลาที่รัดกุมทำให้เกิดการเปลี่ยนแปลงในส่วนที่สำคัญของแอปพลิเคชันโดยไม่ได้ตั้งใจ

การทดสอบเว็บแอปพลิเคชันมักจะประกอบด้วยการประเมินองค์ประกอบของหน้าด้วยสายตาและการประเมินเชิงประจักษ์ของประสิทธิภาพการทำงานของฟังก์ชัน กล่าวอีกนัยหนึ่ง ในการนำทางผ่านส่วนต่างๆ และดำเนินการกับองค์ประกอบไดนามิก

เมื่อเวลาผ่านไปโครงการจะเต็มไปด้วยสิ่งใหม่ ฟังก์ชันการทำงานซึ่งทำให้กระบวนการตรวจสอบงานยาวและซับซ้อนขึ้น การทดสอบหน่วยใช้สำหรับการทำงานอัตโนมัติ

มี 2 ​​วิธีในการสร้างสถานการณ์ทดสอบ:

  • กล่องสีขาวการทดสอบ– การทดสอบการเขียนขึ้นอยู่กับการใช้งานฟังก์ชัน เหล่านั้น. เราตรวจสอบอัลกอริทึมเดียวกันกับที่ทำงานของโมดูลของระบบของเรา วิธีการนี้ไม่ได้รับประกันการทำงานที่ถูกต้องของระบบโดยรวม
  • กล่องดำการทดสอบ– การเขียนสคริปต์ขึ้นอยู่กับข้อกำหนดและความต้องการของระบบ ด้วยวิธีนี้ คุณสามารถตรวจสอบความถูกต้องของผลลัพธ์ของแอปพลิเคชันทั้งหมดได้ แต่วิธีการนี้ไม่อนุญาตให้คุณตรวจจับข้อผิดพลาดเล็กน้อยและเกิดขึ้นได้ยาก

สิ่งที่จะทดสอบ

อาจเป็นความคิดที่ดีที่จะทดสอบคุณลักษณะทั้งหมดที่คุณใช้ สิ่งนี้ไม่เป็นความจริงทั้งหมด การทดสอบการเขียนต้องใช้เวลาของนักพัฒนา ดังนั้นเพื่อเพิ่มประสิทธิภาพกระบวนการทำงานในการสร้างแอปพลิเคชัน จึงควรเตรียมการทดสอบสำหรับฟังก์ชันที่ซับซ้อน สำคัญ หรือฟังก์ชันที่ขึ้นอยู่กับผลลัพธ์ของโมดูลระบบอื่นเท่านั้น ครอบคลุมการทดสอบที่มีตรรกะคลุมเครือซึ่งอาจมีข้อผิดพลาด นอกจากนี้ คุณควรสร้างการทดสอบสำหรับส่วนต่างๆ ของโค้ดที่วางแผนจะปรับให้เหมาะสมในอนาคต เพื่อให้หลังจากกระบวนการปรับให้เหมาะสมแล้ว คุณจะสามารถแน่ใจได้ว่าดำเนินการอย่างถูกต้อง

โดยทั่วไปแล้ว การประเมินต้นทุนการทดสอบเทียบกับเวลาในการพัฒนาที่จำกัดนั้นเป็นสิ่งสำคัญอย่างยิ่ง แน่นอน หากคุณไม่จำกัดเวลา คุณสามารถให้แต่ละฟังก์ชันครอบคลุมการทดสอบได้ แต่ตามกฎแล้ว การพัฒนาจะดำเนินการในช่วงเวลาจำกัด ดังนั้นงานของนักวิเคราะห์หรือนักพัฒนาที่มีประสบการณ์คือการทำความเข้าใจว่าการทดสอบใดที่จำเป็น นอกจากนี้ การทดสอบการเขียนจะเพิ่มต้นทุนของโครงการ

ดังนั้น เราสามารถกำหนดได้ 3 กรณีเมื่อการใช้การทดสอบหน่วยมีความชอบธรรม:

1) หากการทดสอบทำให้สามารถระบุข้อผิดพลาดได้เร็วกว่าการค้นหาตามปกติ

2) ลดเวลาในการดีบัก

3) ให้คุณทดสอบรหัสที่เปลี่ยนแปลงบ่อย

จาก 3 องค์ประกอบหลักของส่วนหน้า (HTML, CSS, JavaScript) อาจจำเป็นต้องทดสอบโค้ด JavaScript เท่านั้น CSS จะถูกตรวจสอบด้วยสายตาเมื่อผู้พัฒนา/ผู้ทดสอบ/ลูกค้าดูเท่านั้น กุยในเบราว์เซอร์ต่างๆ HTML - มาร์กอัปถูกตรวจสอบด้วยวิธีเดียวกัน

วิธีทดสอบ

เมื่อออกแบบสถานการณ์ทดสอบ คุณควรได้รับคำแนะนำจากหลักการต่อไปนี้:

  • การทดสอบของคุณควรจะง่ายที่สุดจากนั้นมีโอกาสมากขึ้นที่ข้อผิดพลาดที่คุณพยายามทำซ้ำจะส่งผลต่อผลลัพธ์ของการใช้งาน
  • แยกย่อยการทดสอบของโมดูลขนาดใหญ่ Grove เพื่อค้นหาตำแหน่งเฉพาะของข้อผิดพลาด
  • ทำการทดสอบอย่างเป็นอิสระผลของการทดสอบหนึ่งไม่ควรขึ้นอยู่กับผลลัพธ์ของการทดสอบอื่น
  • ผลการทดสอบควรทำซ้ำได้อย่างสมบูรณ์และคาดหวังทุกครั้งที่คุณเรียกใช้การทดสอบอีกครั้ง ผลลัพธ์ควรเหมือนกับครั้งล่าสุด
  • สำหรับข้อผิดพลาดในการดำเนินการของแอปพลิเคชัน จะต้องสร้างสคริปต์ทดสอบด้วยวิธีนี้คุณจะมั่นใจได้ว่าข้อบกพร่องได้รับการแก้ไขแล้วจริงๆ และไม่ปรากฏต่อผู้ใช้

วิธีทดสอบ

มีไลบรารีมากมายสำหรับการทดสอบโค้ด js ของหน่วย บางทีที่พบมากที่สุดคือ QUnit ในการดำเนินการทดสอบหน่วยโดยใช้ไลบรารีนี้ เราจำเป็นต้องสร้าง "แซนด์บ็อกซ์" ซึ่งเป็นหน้า html อย่างง่ายที่จะเชื่อมต่อไลบรารีการทดสอบ โค้ดที่จะทดสอบ และการทดสอบเอง

ฟังก์ชั่นสำหรับการทดสอบ:

(ฟังก์ชัน() ( window.stepen = ฟังก์ชัน(int) ( var ผลลัพธ์ = 2; สำหรับ (var i = 1; i< int; i ++) { result = result * 2; } return result; } window.returnFunc = function() { return "ok"; } })();

รายการทดสอบ:

ทดสอบ ("ขั้นตอน ()", ฟังก์ชัน () ( เท่ากับ (ขั้นตอน (2), 4, "2^2 - วิธีเท่ากับ"); ตกลง (ขั้นตอน (3) === 8, "2^3 - วิธีตกลง" ); deepEqual(สเต็ป(5), 32, "2^5 - วิธี deepEqual"); )); asyncTest("returnFunc()", function() ( setTimeout(function() ( เท่ากับ(returnFunc(), "ตกลง", "Async Func Test"); start(); ), 1000); ));

อย่างที่คุณเห็น QUnit รองรับ 3 ฟังก์ชันสำหรับเปรียบเทียบผลลัพธ์ของการดำเนินการโค้ดกับที่คาดไว้:

  • ตกลง()- ถือว่าการทดสอบสำเร็จหากผลลัพธ์ที่ส่งคืน = จริง
  • เท่ากัน()- เปรียบเทียบผลลัพธ์กับที่คาดไว้
  • ลึกเท่ากัน()- เปรียบเทียบผลลัพธ์กับผลลัพธ์ที่คาดหวัง ตรวจสอบประเภทของมัน

ผลการดำเนินการ:

อย่างที่คุณเห็น ไลบรารี QUnit ทดสอบโค้ดสำหรับเบราว์เซอร์หลายตัวพร้อมกัน

มีห้องสมุดอื่น ๆ อีกหลายแห่งสำหรับการทดสอบหน่วย อย่างไรก็ตาม แนวคิดในการสร้างสคริปต์ทดสอบในนั้นเหมือนกัน ดังนั้นเมื่อจัดการกับอันหนึ่งแล้ว คุณจะเปลี่ยนไปใช้อันอื่นได้ไม่ยาก

สิ่งสำคัญที่ต้องจำ

คุณลักษณะของรหัส js สมัยใหม่คือการทำงานแบบอะซิงโครนัส ไลบรารีสำหรับการทดสอบมักจะมีความสามารถในการทำการทดสอบแบบอะซิงโครนัส แต่ตัวอย่างเช่น หากคุณพยายามทดสอบฟังก์ชัน เช่น ส่งคำขอ get ไปยังแบ็กเอนด์และส่งคืนการตอบกลับ จากนั้นเพื่อดำเนินการทดสอบ คุณจะต้องหยุดเธรดด้วยฟังก์ชัน stop() start ฟังก์ชันภายใต้การทดสอบ จากนั้นรีสตาร์ทเธรดด้วยเมธอด start() และ "ห่อมัน" ใน setTimeout() เหล่านั้น. คุณต้องกำหนดช่วงเวลาที่ควรดำเนินการฟังก์ชันให้เสร็จสมบูรณ์ คุณต้องเลือกระยะเวลาของกลุ่มนี้อย่างระมัดระวัง .k ในแง่หนึ่ง การทำงานที่ยาวนานของเมธอดอาจเป็นคุณลักษณะหรือแม้แต่ความจำเป็นสำหรับการใช้งานฟังก์ชันแอ็พพลิเคชันเฉพาะ หรือพฤติกรรมที่ไม่ถูกต้อง

การทดสอบแอปพลิเคชันกระดูกสันหลัง

สำหรับตัวอย่างการทดสอบแอปพลิเคชันที่เขียนโดยใช้ Backbone.js เราจะใช้โครงการที่อธิบายไว้ใน

คุณสามารถตรวจสอบได้ด้วยการทดสอบหน่วย:

  • ความถูกต้องของการสร้างแบบจำลองและตัวควบคุม
  • ความถูกต้องของข้อมูลในแบบจำลอง
  • การดำเนินการของวิธีการควบคุม (สำหรับสิ่งนี้จะต้องส่งคืนผลลัพธ์)
  • ดูความสำเร็จในการโหลด

รหัสทดสอบ:

ทดสอบ ("Backbone.js", ฟังก์ชัน () ( ตกลง (ตัวอย่าง, "ตรวจสอบเนมสเปซ"); ตกลง (sample.routers.app, "ตรวจสอบเราเตอร์"); ตกลง (sample.core.pageManager.open ("แชท") , "การทดสอบการเปิดหน้า (การเรียกใช้เมธอดตัวควบคุม)") ตกลง(sample.core.state, "การตรวจสอบโมเดล"); เท่ากับ(sample.core.state.get("เนื้อหา"), "ซินเทล", "รับข้อมูลโมเดลทดสอบ "); stop(); ok(function() ( $.ajax(( url: "app/templates/about.tpl", dataType: "text" )).done(function(data) ( self.$el. html(data); return data; )) ), "ตรวจสอบการโหลดเทมเพลต"); setTimeout(function() ( start(); ), 1000); ));

ผลลัพธ์ของการทำงานกับข้อผิดพลาดในการทดสอบ:

ทดสอบการทำงานอัตโนมัติ

โดยปกติแล้ว การปรับใช้แอปพลิเคชันเป็นงานที่ต้องทำค่อนข้างบ่อยในระหว่างการพัฒนาอย่างเข้มข้น ดังนั้นการดำเนินการนี้มักจะเป็นไปโดยอัตโนมัติ เราใช้ Jenkins ซึ่งเป็นเครื่องมือบูรณาการอย่างต่อเนื่องในการทำงานของเรา แนวคิดคือการรวมการปรับใช้ผ่าน Jenkins กับการทดสอบอัตโนมัติ

การทดสอบ QUnit ทำงานในเบราว์เซอร์ Phantomjs ซอฟต์แวร์ที่เลียนแบบเบราว์เซอร์จะช่วยให้เราใช้งานคุณสมบัตินี้ได้ นักพัฒนา phantomjs ได้เตรียมสคริปต์สำหรับดำเนินการทดสอบ QUnit ไว้แล้ว แต่ต้องมีการแก้ไขเล็กน้อยเพื่อให้ทำงานได้อย่างถูกต้อง

/** * รอจนกว่าเงื่อนไขการทดสอบจะเป็นจริงหรือหมดเวลา * มีประโยชน์สำหรับการรอ * ในการตอบสนองของเซิร์ฟเวอร์หรือการเปลี่ยนแปลง UI (fadeIn เป็นต้น) ที่จะเกิดขึ้น * * @param testFx เงื่อนไขจาวาสคริปต์ที่ประเมินเป็นบูลีน * สามารถส่งผ่านเป็นสตริง (เช่น: "1 == 1" หรือ * "$("#bar").is(":visible")" หรือ * เป็นฟังก์ชันการโทรกลับ * @param onReady สิ่งที่ต้องทำเมื่อเงื่อนไข testFx สำเร็จ * สามารถส่งผ่านเป็นสตริง (เช่น: "1 == 1" หรือ * "$("#bar").is (":visible")" หรือ * เป็นฟังก์ชันการโทรกลับ * @param timeOutMillis คือระยะเวลาสูงสุดที่จะรอ หากไม่ได้ระบุ * จะใช้ 3 วินาที */ function waitFor(testFx, onReady, timeOutMillis) ( var maxtimeOutMillis = timeOutMillis - timeOutMillis: 3001, //< Default Max Timout is 3s start = new Date().getTime(), condition = false, interval = setInterval(function() { if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) { // If not time-out yet and condition not yet fulfilled condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code } else { if(!condition) { // If condition still not fulfilled // (timeout but condition is "false") console.log(""waitFor()" timeout"); phantom.exit(1); } else { // Condition fulfilled (timeout and/or condition is //"true") console.log(""waitFor()" finished in " + (new Date().getTime() - start) + "ms."); typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it"s supposed to do once the // condition is fulfilled clearInterval(interval); //< Stop this interval } } }, 100); // repeat check every 250ms }; }; if (phantom.args.length === 0 || phantom.args.length >2) console.log("การใช้งาน: run-qunit.js URL"); phantom.exit(); ) var page = หน้าเว็บใหม่ (); // กำหนดเส้นทางการเรียก "console.log()" จากภายในเพจ // บริบทไปยังบริบท Phantom หลัก (เช่น ปัจจุบัน "นี้") page.onConsoleMessage = function(msg) ( console.log(msg); ); page.open(phantom.args, function(status)( if (status !== "success") ( console.log("Unable to access network"); phantom.exit(); ) else ( waitFor(function() ( return page.evaluate(function()( var el = document.getElementById("qunit-testresult"); if (el && el.innerText.match("completed")) ( return true; ) return false; )); ), ฟังก์ชัน()( var failedNum = page.evaluate(ฟังก์ชัน()( var el = document.getElementById("qunit-testresult"); console.log(el.innerText); try ( return document.getElementsByClassName("fail" ).innerHTML.length; ) catch (e) ( return 0; ) return 10,000; )); phantom.exit((parseInt(failedNum, 10) > 0) ? 1: 0); )); ) ));

หากต้องการแสดงข้อความผลลัพธ์ในคอนโซล คุณต้องเพิ่มฟังก์ชันการบันทึกลงในสคริปต์ทดสอบ

ขณะนี้ไซต์มีการทดสอบความรู้ในหัวข้อต่อไปนี้: HTML, css, จาวาสคริปต์, พี.เอช.พี, เอสคิวแอล.

แต่ละการทดสอบประกอบด้วย 10คำถามในหัวข้อเฉพาะ ในแต่ละคำถาม ฉันพยายามที่จะสัมผัสกับขอบเขตที่หลากหลายที่สุดของการประยุกต์ใช้ภาษาใดภาษาหนึ่งเพื่อตรวจสอบระดับความรู้ของคุณอย่างละเอียดที่สุด

แน่นอนทุกอย่าง การทดสอบฟรีและทุกคนสามารถผ่านไปได้

กระบวนการทดสอบ:

  1. ตามลิงค์" เริ่มการทดสอบ"ของการทดสอบที่เกี่ยวข้อง
  2. ตอบคำถามโดยเลือก เพียงผู้เดียว, เพียงคนเดียวตัวเลือกที่ถูกต้อง
  3. เมื่อเสร็จสิ้นการทดสอบคุณจะเห็น คะแนนของคุณ, จำนวนข้อผิดพลาด, และ การวิเคราะห์คำถามแต่ละข้อจากการทดสอบ

ความสนใจ!การกลับไปที่คำถามก่อนหน้าจะไม่ทำงาน ดังนั้นก่อนที่จะตอบ ให้คิด

การทดสอบที่มีอยู่ในปัจจุบัน

  1. HTML

    • ผ่านการทดสอบทั้งหมด: 75424 คน
    • คะแนนเฉลี่ย: 2.83 จาก 5คะแนน

    แบบทดสอบความรู้พื้นฐาน HTML. คุณจะต้องรู้พื้นฐาน แท็ก HTMLและการใช้งานที่เหมาะสม นอกจากนี้ยังจำเป็นต้องเข้าใจคุณสมบัติของมาตรฐาน เอ็กซ์เอชทีเอ็มแอล 1.1.

  2. css

    • ผ่านการทดสอบทั้งหมด: 32828 คน
    • คะแนนเฉลี่ย: 3.37 จาก 5คะแนน

    แบบทดสอบจะทดสอบความรู้พื้นฐาน css. เพื่อให้ผ่านการทดสอบได้สำเร็จ คุณต้องรู้ประเภทพื้นฐานของตัวเลือก (ไวยากรณ์) รู้คุณสมบัติพื้นฐานและค่าที่เป็นไปได้ และรู้จุดประสงค์ขององค์ประกอบเทียมที่ได้รับความนิยมมากที่สุดด้วย

  3. จาวาสคริปต์

    • ผ่านการทดสอบทั้งหมด: 24845 คน
    • คะแนนเฉลี่ย: 3.31 จาก 5คะแนน

    แบบทดสอบนี้ทดสอบความรู้ของคุณเกี่ยวกับภาษา JavaScript คำถามจากการทดสอบครอบคลุมการใช้งานในด้านต่างๆ ภาษาที่กำหนด. มีคำถามมากมายเกี่ยวกับการทำความเข้าใจความแตกต่าง "เล็กน้อย" มิฉะนั้น คุณจะต้องรู้เรื่องพื้นฐาน: การทำงานกับตัวแปร ฟังก์ชัน JavaScript พื้นฐาน ลำดับความสำคัญของตัวดำเนินการ และอื่นๆ

  4. พี.เอช.พี

    • ผ่านการทดสอบทั้งหมด: 33239 คน
    • คะแนนเฉลี่ย: 3.03 จาก 5คะแนน

    แบบทดสอบนี้ทดสอบความรู้ของคุณเกี่ยวกับภาษา PHP คุณจำเป็นต้องรู้โครงสร้าง PHP พื้นฐาน การทำงานกับตัวแปร เซสชัน การใช้งานการเปลี่ยนเส้นทาง และมาตรฐานอื่นๆ
    คำขอที่น่าเชื่อถือ:การทดสอบมีคำถามมากมายเช่น: "สคริปต์จะออกอะไร" คำขอใหญ่ อย่าคัดลอกและตรวจสอบ ซื่อสัตย์กับตัวเอง

  5. เอสคิวแอล

    • ผ่านการทดสอบทั้งหมด: 18014 คน
    • คะแนนเฉลี่ย: 3.28 จาก 5คะแนน

    แบบทดสอบนี้ทดสอบความรู้ภาษาของคุณ แบบสอบถาม SQL. คำถามครอบคลุมเฉพาะความรู้พื้นฐานที่สุดของภาษานี้โดยไม่มีการเจาะลึกใดๆ คุณจะต้องมีความรู้เกี่ยวกับการสืบค้น SQL พื้นฐานที่สุด รวมถึงการใช้งานอย่างเชี่ยวชาญ

ในตัวอย่างแอปพลิเคชันเครื่องคิดเลขอย่างง่ายบน Node.js เราจะทดสอบโดยใช้ Mocha framework

แอปพลิเคชันของเราควรทำอะไรได้บ้าง:

  • บวก ลบ หาร และคูณสองจำนวน;
  • แสดงคำเตือนและออกหากมีการป้อนอย่างอื่นที่ไม่ใช่ตัวเลข
  • ต้องมีอินเทอร์เฟซบรรทัดคำสั่งเพื่อให้ผู้ใช้สามารถใช้แอปพลิเคชันได้

สิ่งที่เราต้องการ:

  • Node.js และ npm
  • ความรู้เกี่ยวกับจาวาสคริปต์: ไวยากรณ์และโครงสร้างรหัส ชนิดข้อมูล การดำเนินการทางคณิตศาสตร์ และนิพจน์เงื่อนไข

เมื่อกำหนดเป้าหมายแล้ว คุณสามารถเริ่มตั้งค่าสภาพแวดล้อมสำหรับการทดสอบและพัฒนาได้

การตั้งค่าสภาพแวดล้อม

เนื่องจากเราใช้ Node.js เราจึงจำเป็นต้องสร้างสภาพแวดล้อมในเครื่องสำหรับไฟล์และการอ้างอิง

สร้าง แฟ้มใหม่ คำนวณ. ในบรรทัดคำสั่ง เปลี่ยนเป็นไดเร็กทอรีนี้และสร้างโปรเจ็กต์ใหม่ด้วย npm init ซึ่งจะสร้าง ไฟล์ใหม่ package.jsonสำหรับโปรแกรมของเรา

คุณจะได้รับแจ้งให้ป้อนชื่อแพ็คเกจ รุ่น คำอธิบาย และข้อมูลอื่น ๆ เกี่ยวกับแพ็คเกจ คุณสามารถป้อนชื่อ calc.jsและกดไปเรื่อยๆ เข้าเพื่อกำหนดค่าเริ่มต้น เมื่อคุณไปถึง test command ให้พิมพ์ mocha - นี่คือกรอบการทดสอบที่เราจะใช้:

คำสั่งทดสอบ: มอคค่า

หลังจากป้อนข้อมูลทั้งหมดสคริปต์จะสร้างไฟล์ package.jsonซึ่งมีลักษณะดังนี้:

( "name": "calc.js", "version": "1.0.0", "description": "เครื่องคิดเลขอย่างง่ายใน Node.js", "main": "index.js", "scripts": ( " ทดสอบ": "มอคค่า" ), "ผู้เขียน": "", "ใบอนุญาต": "ISC" )

ขั้นตอนสุดท้ายในขั้นตอนนี้คือการติดตั้ง Mocha ป้อนคำสั่งต่อไปนี้เพื่อติดตั้ง:

npm ติดตั้ง --save-dev มอคค่า

หลังจากใช้คำสั่งนี้ โฟลเดอร์จะปรากฏขึ้น node_modules, ไฟล์ package-lock.jsonและในไฟล์ package.jsonบรรทัดต่อไปนี้จะปรากฏขึ้น:

"devDependencies": ( "มอคค่า": "^4.0.1" )

สร้างไฟล์ ทดสอบ js. เราจะใช้โมดูลในตัวใน Node.js ยืนยันเพื่อตรวจสอบว่าจริงหรือไม่จริง เนื่องจากเป็นความจริง การทดสอบควรผ่าน:

Const ยืนยัน = ต้องการ ("ยืนยัน"); it("ควรคืนค่าจริง", () => ( assert.equal(จริง, จริง); ));

ตอนนี้รันการทดสอบจากบรรทัดคำสั่ง:

การทดสอบ $ npm > mocha ✓ ควรคืนค่าจริง 1 ผ่าน (8ms)

การทดสอบเป็นไปตามที่คาดไว้ ดังนั้นการตั้งค่าสภาพแวดล้อมจึงเสร็จสิ้น ลบออกจาก ทดสอบ jsทุกอย่างยกเว้นบรรทัด const assert = required("assert"); .

เราจะใช้ไฟล์ ทดสอบ jsตลอดกระบวนการพัฒนาแอปพลิเคชัน สร้างอีกสองไฟล์: operation.jsสำหรับฟังก์ชันเลขคณิตและการตรวจสอบ และ calc.jsสำหรับการสมัครนั่นเอง เราใช้ไฟล์จำนวนมากเพื่อไม่ให้ยาวและซับซ้อนเกินไป นี่คือรายการไฟล์ปัจจุบันของเรา:

  • calc.js;
  • node_modules;
  • operation.js;
  • package-lock.json;
  • package.json;
  • ทดสอบ js;

มาเพิ่มอันแรกกัน การทดสอบจริงสำหรับการสมัครของเรา

การเพิ่มการดำเนินการทางคณิตศาสตร์

ก่อนอื่น แอปพลิเคชันของเราต้องสามารถบวก ลบ หาร และคูณจำนวนสองจำนวนใดๆ ดังนั้นสำหรับการดำเนินการแต่ละอย่าง เราต้องสร้างฟังก์ชันแยกต่างหาก

เริ่มจากการเพิ่มกันก่อน เราจะเขียนแบบทดสอบที่ได้ผลรวมของตัวเลขสองตัวโดยไม่ซ้ำกัน ในโค้ดด้านล่าง เราตรวจสอบว่าผลรวมของ 1 และ 3 เท่ากันหรือไม่โดยใช้ฟังก์ชัน add() 4:

Const ยืนยัน = ต้องการ ("ยืนยัน"); it("หาผลรวมของ 1 และ 3 ได้อย่างถูกต้อง", () => ( assert.equal(add(1, 3), 4); ));

หลังจากรันการทดสอบด้วยคำสั่ง npm test เราจะเห็นสิ่งต่อไปนี้:

> mocha 0 ผ่าน (9ms) 1 ล้มเหลว 1) ค้นหาผลรวมของ 1 และ 3 อย่างถูกต้อง: ReferenceError: เพิ่มไม่ได้กำหนดไว้ที่ Context.it (test.js:5:16) npm ERR! การทดสอบล้มเหลว ดูด้านบนสำหรับรายละเอียดเพิ่มเติม

การทดสอบล้มเหลวด้วย ReferenceError: ไม่ได้กำหนด add เรากำลังทดสอบฟังก์ชัน add() ซึ่งยังไม่มีอยู่ ดังนั้นผลลัพธ์นี้จึงค่อนข้างคาดหวังไว้

มาสร้างฟังก์ชัน add() ในไฟล์กันเถอะ operation.js:

Const บวก = (x, y) => (+x) + (+y);

ฟังก์ชันนี้รับอาร์กิวเมนต์ x และ y สองตัวและส่งกลับผลรวม คุณอาจสังเกตว่าเราเขียน (+x) + (+y) แทน x + y เราใช้ตัวดำเนินการยูนารีในการส่งอาร์กิวเมนต์เป็นตัวเลข ในกรณีที่อินพุตเป็นสตริง

หมายเหตุ สิ่งนี้ใช้ฟังก์ชันลูกศรที่เพิ่ม ES6 และการส่งคืนโดยปริยาย

เนื่องจากเราใช้ Node.js และแบ่งโค้ดออกเป็นหลายๆ ไฟล์ เราจึงจำเป็นต้องใช้ module.exports เพื่อส่งออกโค้ด:

Const บวก = (x, y) => (+x) + (+y); module.exports = ( เพิ่ม )

ที่จุดเริ่มต้นของไฟล์ ทดสอบ jsเรานำเข้ารหัสจาก operation.jsด้วย need() . เนื่องจากเราใช้ฟังก์ชันผ่านตัวแปร operation เราจึงจำเป็นต้องเปลี่ยน add() เป็น operation.add() :

การดำเนินการ Const = ต้องการ ("./operations.js"); const ยืนยัน = ต้องการ ("ยืนยัน"); it("หาผลรวมของ 1 และ 3 ได้อย่างถูกต้อง", () => ( assert.equal(operations.add(1, 3), 4); ));

มาทำการทดสอบกัน:

การทดสอบ $ npm > mocha ✓ ค้นหาผลรวมของ 1 และ 3 ได้อย่างถูกต้อง 1 ผ่าน (8ms)

ตอนนี้เรามีฟังก์ชั่นการทำงานและการทดสอบก็ผ่านไปด้วยดี เนื่องจากฟังก์ชันของการดำเนินการอื่นๆ ทำงานในลักษณะเดียวกัน การเพิ่มการทดสอบสำหรับการลบ() คูณ() และหาร() จึงเป็นเรื่องง่าย:

It("หาผลรวมของ 1 และ 3 ได้อย่างถูกต้อง", () => ( assert.equal(operations.add(1, 3), 4); )); it("หาผลรวมของ -1 และ -1 ได้อย่างถูกต้อง", () => ( assert.equal(operations.add(-1, -1), -2); )); it("พบความแตกต่างระหว่าง 33 และ 3 อย่างถูกต้อง", () => ( assert.equal(operations.subtract(33, 3), 30); )); it("ค้นหาผลคูณของ 12 และ 12 ได้อย่างถูกต้อง", () => ( assert.equal(operations.multiply(12, 12), 144); )); it("หาผลหารของ 10 และ 2 ได้อย่างถูกต้อง", () => ( assert.equal(operations.divide(10, 2), 5); ));

ตอนนี้มาสร้างและส่งออกฟังก์ชันทั้งหมดไปที่ ทดสอบ js:

Const บวก = (x, y) => (+x) + (+y); ลบ const = (x, y) => (+x) - (+y); const คูณ = (x, y) => (+x) * (+y); const หาร = (x, y) => (+x) / (+y); module.exports = ( บวก ลบ คูณ หาร )

และเรียกใช้การทดสอบใหม่:

$npm test > mocha ✓ หาผลรวมของ 1 กับ 3 ได้ถูกต้อง ✓ หาผลรวมของ -1 กับ -1 ได้ถูกต้อง ✓ หาผลต่างระหว่าง 33 กับ 3 ได้ถูกต้อง ✓ หาผลคูณของ 12 กับ 12 ได้ถูกต้อง ✓ หาผลหารของ 10 ได้ถูกต้อง และ 2 5 ผ่านไป (8ms)

การทดสอบทั้งหมดผ่านเรียบร้อยแล้ว ดังนั้นตอนนี้เราจึงมั่นใจได้ว่าฟังก์ชันหลักของแอปพลิเคชันของเราจะทำงานได้อย่างถูกต้อง ตอนนี้เราสามารถทำการตรวจสอบเพิ่มเติมได้

การเพิ่มการตรวจสอบ

ในขณะนี้ เมื่อผู้ใช้ป้อนตัวเลขและเลือกการดำเนินการที่ต้องการ ทุกอย่างก็ทำงานได้ดี อย่างไรก็ตาม จะเกิดอะไรขึ้นหากคุณพยายามหาผลรวมของตัวเลขและสตริง แอปพลิเคชันจะพยายามดำเนินการ แต่เนื่องจากคาดว่าจะมีตัวเลข จึงจะส่งกลับ NaN

แทนที่จะส่งคืนค่าแปลก ๆ ถึงเวลาที่ต้องทำงานที่สอง - เพื่อให้แอปพลิเคชันแสดงคำเตือนและออกหากอาร์กิวเมนต์อินพุตไม่ใช่ตัวเลข

ก่อนอื่นคุณต้องเขียนฟังก์ชันที่จะตรวจสอบว่าอินพุตเป็นตัวเลขหรือไม่ แอปพลิเคชันควรทำงานกับตัวเลขเท่านั้น ดังนั้นเราจะจัดการกับสามสถานการณ์:

  1. อินพุตทั้งสองเป็นตัวเลข
  2. อินพุตหนึ่งเป็นตัวเลขและอีกอินพุตเป็นสตริง
  3. อินพุตทั้งสองเป็นสตริง
it("รายงานข้อผิดพลาดเมื่อใช้สตริงแทนตัวเลข", () => ( assert.equal(operations.validateNumbers("sammy", 5), false); )); it("รายงานข้อผิดพลาดเมื่อใช้สองสตริงแทนตัวเลข", () => ( assert.equal(operations.validateNumbers("sammy", "sammy"), false); )); it("สำเร็จเมื่อใช้ตัวเลขสองตัว", () => ( assert.equal(operations.validateNumbers(5, 5), true); ));

ฟังก์ชัน validateNumbers() จะตรวจสอบพารามิเตอร์ทั้งสอง ฟังก์ชัน isNaN() จะตรวจสอบว่าพารามิเตอร์ไม่ใช่ตัวเลขหรือไม่ และถ้าไม่ใช่ จะคืนค่าเป็นเท็จ มิฉะนั้น จะคืนค่าจริง ซึ่งหมายถึงการตรวจสอบสำเร็จ

Const validateNumbers = (x, y) => ( if (isNaN(x) && isNaN(y)) ( return false; ) return true; )

อย่าลืมเพิ่ม validateNumbers ใน module.exports ที่ส่วนท้ายของไฟล์ ตอนนี้คุณสามารถเรียกใช้การทดสอบใหม่:

การทดสอบ $npm 1) รายงานข้อผิดพลาดเมื่อใช้สตริงแทนตัวเลข ✓ รายงานข้อผิดพลาดเมื่อใช้สองสตริงแทนตัวเลข ✓ สำเร็จเมื่อใช้ตัวเลขสองตัว 7 ผ่าน (12ms) 1 ล้มเหลว 1) รายงานข้อผิดพลาดเมื่อใช้สตริงแทน จากจำนวน: AssertionError : จริง == เท็จ + ที่คาดไว้ - จริง -จริง + เท็จ

การทดสอบสองครั้งผ่าน แต่การทดสอบหนึ่งล้มเหลว การทดสอบสำหรับตัวเลขสองตัวประสบความสำเร็จเช่นเดียวกับการทดสอบสำหรับสองสาย สิ่งที่ไม่สามารถพูดได้เกี่ยวกับการตรวจสอบอินพุตของสตริงและตัวเลข

ถ้าเราดูหน้าที่ของเราอีกครั้ง เราจะเห็นว่า ทั้งคู่พารามิเตอร์ต้องเป็น NaN เพื่อให้ฟังก์ชันส่งคืนค่าเท็จ หากเราต้องการบรรลุผลแบบเดียวกันเมื่อพารามิเตอร์อย่างน้อยหนึ่งตัวคือ NaN เราจำเป็นต้องแทนที่ && ด้วย || :

Const validateNumbers = (x, y) => ( if (isNaN(x) || isNaN(y)) ( return false; ) return true; )

หากคุณเรียกใช้การทดสอบ npm อีกครั้งหลังจากการเปลี่ยนแปลงเหล่านี้ การทดสอบทั้งหมดจะผ่าน:

✓ รายงานข้อผิดพลาดเมื่อใช้สตริงแทนตัวเลข ✓ รายงานข้อผิดพลาดเมื่อใช้สองสตริงแทนตัวเลข ✓ สำเร็จเมื่อใช้สองตัวเลข 8 ผ่าน (9ms)

เราได้ทดสอบการทำงานทั้งหมดของแอปพลิเคชันของเราแล้ว ฟังก์ชันดำเนินการทางคณิตศาสตร์และตรวจสอบอินพุตได้สำเร็จ ขั้นตอนสุดท้ายคือการสร้างส่วนติดต่อผู้ใช้

การสร้างอินเทอร์เฟซ

เรามีฟังก์ชั่นที่จำเป็นอยู่แล้ว แต่ผู้ใช้ยังไม่สามารถใช้งานได้ในทางใดทางหนึ่ง ดังนั้นเราจึงต้องการอินเทอร์เฟซ สำหรับแอปพลิเคชันของเรา เราจะสร้างอินเทอร์เฟซบรรทัดคำสั่ง

ในขณะนี้ไฟล์ calc.jsควรว่างเปล่า นี่คือที่ที่แอปพลิเคชันของเราจะถูกเก็บไว้ ก่อนอื่นคุณต้องนำเข้าฟังก์ชันจาก operation.js:

การดำเนินการ Const = ต้องการ ("./operations.js");

อินเทอร์เฟซจะใช้โมดูล Readline CLI ในตัวของ Node.js:

Const readline = ต้องการ ("อ่านบรรทัด");

หลังจากนำเข้าทุกสิ่งที่คุณต้องการแล้ว คุณสามารถเริ่มสร้างแอปพลิเคชันได้ ในการสร้างอินเทอร์เฟซ เราจะใช้ readline ซึ่งมีให้ผ่านตัวแปร rl:

Const rl = readline.createInterface (( อินพุต: process.stdin, เอาต์พุต: process.stdout ));

สิ่งแรกที่ผู้ใช้ควรเห็นหลังจากเริ่มโปรแกรมคือข้อความต้อนรับและคำแนะนำในการใช้งาน ในการทำเช่นนี้ เราจะใช้ console.log() :

Console.log(` Calc.js คุณเปิดเครื่องคิดเลข Node.js แล้ว! เวอร์ชัน: 1.0.0. การใช้งาน: ผู้ใช้ต้องป้อนตัวเลขสองตัว จากนั้นเลือกว่าจะทำอย่างไรกับตัวเลขเหล่านั้น `);

ก่อนที่เราจะเข้าสู่ฟังก์ชันเครื่องคิดเลข เรามาตรวจดูว่า console.log() ทำงานได้อย่างที่ควรจะเป็นหรือไม่ เราจะให้โปรแกรมพิมพ์ข้อความและออก เมื่อต้องการทำเช่นนี้ เพิ่มการเรียกเมธอด rl.close() ในตอนท้าย

ในการเรียกใช้แอปพลิเคชัน ให้ป้อน node ตามด้วยชื่อไฟล์:

$ node calc.js Calc.js คุณได้เปิดเครื่องคิดเลข Node.js แล้ว! เวอร์ชัน: 1.0.0. การใช้งาน: ผู้ใช้ต้องป้อนตัวเลขสองตัว จากนั้นเลือกว่าจะทำอย่างไรกับตัวเลขเหล่านี้

โปรแกรมแสดงข้อความต้อนรับและออก ตอนนี้เราต้องเพิ่มอินพุตของผู้ใช้ ผู้ใช้จำเป็นต้องเลือกสองหมายเลขและหนึ่งการดำเนินการ แต่ละอินพุตจะถูกร้องขอโดยเมธอด rl.question():

Rl.question("ป้อนหมายเลขแรก: ", (x) => ( rl.question("ป้อนหมายเลขที่สอง: ", (y) => ( rl.question(` เลือกหนึ่งในการดำเนินการต่อไปนี้: เพิ่ม ( +) ลบ (-) คูณ (*) หาร (/) ทางเลือกของคุณ: `, (choice) => ( // รหัสเพิ่มเติมจะปรากฏที่นี่ rl.close(); )); )); ));

ตัวแปร x ถูกกำหนดให้เป็นตัวเลขแรก y เป็นตัวเลขที่สอง และตัวเลือกคือการดำเนินการที่เลือก ตอนนี้โปรแกรมของเราขออินพุต แต่ไม่ทำอะไรกับข้อมูลที่ได้รับ

หลังจากป้อนครั้งที่สาม คุณต้องตรวจสอบว่าป้อนเฉพาะตัวเลขแล้ว ในการทำเช่นนี้ เราจะใช้ฟังก์ชัน validateNumbers() การใช้ตัวดำเนินการ NOT เราจะตรวจสอบว่ามีการป้อนตัวเลขหรือไม่ หากไม่ใช่ ให้ออกจากโปรแกรม:

ถ้า (!operations.validateNumbers(x, y)) ( console.log("ใช้ได้เฉพาะตัวเลขเท่านั้น! โปรดรีสตาร์ทโปรแกรม"); )

หากป้อนทุกอย่างถูกต้อง ตอนนี้คุณต้องเรียกใช้วิธีการดำเนินการที่เกี่ยวข้องซึ่งสร้างไว้ก่อนหน้านี้ ในการประมวลผลตัวเลือกที่เป็นไปได้ทั้งสี่ เราจะใช้คำสั่ง switch และแสดงผลลัพธ์ของการดำเนินการออกมา หากเลือกการดำเนินการที่ไม่มีอยู่ บล็อกเริ่มต้นจะถูกดำเนินการโดยบอกให้ผู้ใช้ลองอีกครั้ง:

ถ้า (!operations.validateNumbers(x, y)) ( console.log("สามารถป้อนได้เฉพาะตัวเลข! โปรดเริ่มโปรแกรมใหม่"); ) อื่น ( สวิตช์ (ตัวเลือก) ( กรณี "1": console.log(` ผลรวม $(x) และ $(y) เท่ากับ $(operations.add(x, y)).`); break; case "2": console.log(`Difference of $(x) and $(y)เท่ากับ $( operation.subtract(x, y)).`); break; case "3": console.log(`ผลคูณของ $(x) และ $(y) เท่ากับ $(operations.multiply(x, y) ).`) ; break; case "4": console.log(`Private $(x) and $(y)เท่ากับ $(operations.divide(x, y)).`); break; default: console.log ("โปรดเริ่มโปรแกรมใหม่และเลือกตัวเลขระหว่าง 1 ถึง 4"); break; ) )

หมายเหตุ ฟังก์ชัน console.log() ที่นี่ใช้สตริงแม่แบบที่อนุญาตนิพจน์

/** * เครื่องคิดเลข Node.js อย่างง่ายที่ใช้แอพเครื่องคิดเลขที่ใช้ * อินเทอร์เฟซบรรทัดคำสั่ง Readline ในตัว */ การดำเนินการ const = ต้องการ ("./operations.js"); const readline = ต้องการ ("อ่านบรรทัด"); // ใช้ readline เพื่อสร้างอินเตอร์เฟส const rl = readline.createInterface(( input: process.stdin, output: process.stdout )); console.log(` Calc.js คุณเปิดเครื่องคิดเลข Node.js แล้ว! เวอร์ชัน: 1.0.0 การใช้งาน: ผู้ใช้ต้องป้อนตัวเลขสองตัว จากนั้นเลือกว่าจะทำอย่างไรกับตัวเลขเหล่านั้น `); rl.question("ป้อนหมายเลขแรก: ", (x) => ( rl.question("ป้อนหมายเลขที่สอง: ", (y) => ( rl.question(` เลือกหนึ่งในการดำเนินการต่อไปนี้: เพิ่ม ( +) ลบ (-) คูณ (*) หาร (/) ทางเลือกของคุณ: `, (choice) => ( if (!operations.validateNumbers(x, y)) ( console.log("You can enter only number! Please รีสตาร์ทโปรแกรม "); ) else ( switch (choice) ( case "1": console.log(`ผลรวมของ $(x) และ $(y) เท่ากับ $(operations.add(x, y)). `); break; case "2": console.log(`ความแตกต่างระหว่าง $(x) และ $(y) คือ $(operations.subtract(x, y)).`); break; case "3": console.log(`ผลคูณของ $( x) และ $(y) เท่ากับ $(operations.multiply(x, y)).`); break; case "4": console.log(`Private $(x) และ $(y) เท่ากับ $(operations.divid(x, y)).`); break; default: console.log("กรุณารีสตาร์ทโปรแกรมและเลือกตัวเลขระหว่าง 1 ถึง 4"); break; ) ) rl.close(); )); )) ; ));

ตอนนี้ใบสมัครของเราพร้อมแล้ว ตรวจสอบการทำงานของเขาในตอนท้าย ป้อน 999 และ 1 แล้วเลือกการดำเนินการลบ:

$ node calc.js ป้อนหมายเลขแรก: 999 ป้อนหมายเลขที่สอง: 1 ทางเลือกของคุณ: 2 ผลต่างระหว่าง 999 และ 1 คือ 998

โปรแกรมทำงานสำเร็จแสดงผลถูกต้อง ขอแสดงความยินดี คุณได้เขียนเครื่องคิดเลขอย่างง่ายโดยใช้ Node.js และได้เรียนรู้พื้นฐานการพัฒนา TDD



กำลังโหลด...
สูงสุด