แนวทางปฏิบัติที่ดีที่สุดสำหรับ TDD ใน JavaScript/TypeScript
คำถาม
- วิธีที่ถูกต้อง/สามารถยอมรับได้ในการเข้าถึงฟังก์ชัน JavaScript/TypeScript ทั้งหมดในโมดูลสำหรับการทดสอบหน่วยคืออะไร?
- มีเหตุผล (ดี) ที่ทำไมฉันไม่ควรส่งออกฟังก์ชันทั้งหมดของฉันหรือไม่?
บริบท
โปรดให้อภัยในความไม่รู้ของผม; ผมใช้เวลาเกือบทั้งหมดในอาชีพการทำงานของผมเขียนโค้ด Python โดยใช้แนวทาง Test Driven Development (TDD) ตอนนี้ ผมกำลังเรียนรู้ ReactJS/TypeScript และพยายามหาวิธีการทำ unit tests แต่ผมพบอย่างรวดเร็วว่าฟังก์ชันสามารถเข้าถึงได้ก็ต่อเมื่อคุณทำการ export ฟังก์ชันเหล่านั้น อย่างที่หลายคนทราบ Python มีความยืดหยุ่นมากจริง ๆ; จริง ๆ แล้วไม่มีแนวคิดเรื่องความเป็นส่วนตัว ดังนั้นมันจึงเป็นเรื่องของการ import โมดูลและเคารพสิ่งที่คุณสามารถเข้าถึงได้ แต่ JavaScript จะ import เฉพาะฟังก์ชันของโมดูลที่ถูก export อย่างชัดเจนเท่านั้น ทำให้มีอุปสรรคเล็กน้อย
ฉันถูกบอกมาว่าไม่ใช่ความคิดที่ดีที่จะส่งออกฟังก์ชันทั้งหมดของฉันเพื่อทดสอบ แต่ฉันไม่รู้วิธีอื่นที่จะสามารถทดสอบมันได้จริง ๆ
ตัวอย่าง
สิ่งที่ฉันได้รับการบอกคือ “ถูกต้อง/ดีกว่า”:
Sample1.js:
const func1 = () => {
//code that does stuff
return "stuff";
};
const func2 = () => {
//code that does other stuff
return "otherStuff";
};
export { func1 };
Sample1.test.js:
// executed via Jest framework
import * as sample from "./Sample1.js"
describe("Unit Tests for Sample1", () => {
test("Unit Test - func1", () => {
// code that tests stuff
};
test("Unit Test - func2", () => {
// can't test func2 because it's not exported
};
};
สิ่งที่ฉันกำลังทำเพื่อให้สามารถทดสอบฟังก์ชันทั้งหมด:
Sample2.js:
const func1 = () => {
//code that does stuff
return "stuff";
};
const func2 = () => {
//code that does other stuff
return "otherStuff";
};
export { func1, func2 };
Sample2.test.js:
// executed via Jest framework
import * as sample from "./Sample2.js"
describe("Unit Tests for Sample2", () => {
test("Unit Test - func1", () => {
// code that tests stuff
};
test("Unit Test - func2", () => {
// code that tests other stuff because it's exported
};
};
เพื่อเป็นหลักฐาน
ฉันได้ค้นหาข้อมูลบนอินเทอร์เน็ตและโดยเฉพาะใน Stack Overflow เกี่ยวกับมาตรฐานและแนวทางปฏิบัติที่ดีที่สุด แต่ฉันยังไม่พบข้อมูลมากนักที่ตอบคำถามเฉพาะนี้ สิ่งที่ใกล้เคียงที่สุดที่ฉันพบคือคำถามใน SO นี้ แต่ก็ไม่ใช่สิ่งที่ฉันต้องการจริงๆ
คำตอบ #1
ถ้าคุณกำลังทำการพัฒนาด้วยการทดสอบก่อน (TDD) จริง ๆ โดยการเขียนการทดสอบ ก่อนที่ระบบที่กำลังทดสอบ (SUT) คุณสามารถมองว่าการทดสอบเหล่านี้เป็นข้อกำหนดที่สามารถรันได้ของ SUT (ฉันขอโทษหากสิ่งนี้ชัดเจนอยู่แล้วสำหรับคุณ แต่หลายคนที่นี่บน Stack Overflow ใช้คำว่า TDD สลับกับการทดสอบหน่วย และบอกว่าพวกเขาทำ TDD แม้ว่าพวกเขาจะเขียนการทดสอบหลังจาก SUT ก็ตาม)
ดังนั้น การทดสอบจึงอธิบาย API ของ SUT ในภาษาที่มีตัวปรับแต่งการเข้าถึงและ/หรือคุณสมบัติการส่งออกแบบชัดเจน คุณจะต้องทำให้ SUT สามารถเข้าถึงได้ในการทดสอบ ใน JavaScript นี่หมายความว่าคุณจะต้องส่งออก API ที่คุณต้องการทดสอบ ในภาษาคอื่นที่มีตัวปรับแต่งการเข้าถึง นี่ก็หมายความว่าคุณจะต้องให้ API ของ SUT มีความสามารถในการเข้าถึงแบบ public (เช่น ตัวอย่างเช่น Java และ C#)
หากคุณกำลังพัฒนาห้องสมุด สิ่งนี้ก็จะตรงกับ API ที่มีให้กับโค้ดของลูกค้าเช่นกัน ในความเป็นจริง การทดสอบคือผู้ใช้คนแรก (หรือผู้ใช้ที่เร็วที่สุด) ของ SUT
เมื่อการทดสอบถูกติดตั้งแล้ว พวกมันจะทำหน้าที่เป็นชุดทดสอบการถดถอยสำหรับ SUT ดังนั้น หากการทดสอบล้มเหลว มันจะบอกคุณว่าบางส่วนของ API ที่ส่งออกเสียหาย ซึ่งนั่นยังหมายความว่าส่วนดังกล่าวจะเสียหายสำหรับโค้ดของลูกค้าที่ใช้งานมันด้วย
แล้วคุณควรส่งออก ทุก วิธีไหม?
ไม่จำเป็นเสมอไป คุณอาจต้องการเก็บบางวิธีไว้เป็นความลับในฐานะรายละเอียดการนำไปใช้งาน อาจมีเหตุผลดีๆ หลายประการสำหรับเรื่องนี้ บางทีคุณอาจไม่แน่ใจว่า API ของวิธีช่วยเหลือนั้นมีความมั่นคง และคุณต้องการรักษาความสามารถในการเปลี่ยนแปลงโดยไม่ทำให้รหัสของลูกค้าพัง บางทีวิธีช่วยเหลืออาจมีการห่อหุ้มที่ไม่ดี
ตราบใดที่วิธีช่วยเหลือดังกล่าวถูกสร้างขึ้นในระหว่างกระบวนการ TDD พวกมันก็ยังคงถูกครอบคลุมโดยการทดสอบแบบอ้อมแม้ว่าตัวมันเองจะไม่ได้ถูกส่งออกก็ตาม