ในโลกแห่งความจริงมันเป็นเรื่องปกติอย่างสมบูรณ์แบบในการเขียนบททดสอบหน่วยสำหรับรหัสของคนอื่น แน่นอนว่านักพัฒนาดั้งเดิมควรทำสิ่งนี้ไปแล้ว แต่บ่อยครั้งที่คุณได้รับรหัสเดิมซึ่งสิ่งนี้ไม่ได้ทำ อย่างไรก็ตามมันไม่สำคัญว่ารหัสมรดกนั้นมาจากทศวรรษที่ผ่านมาจากกาแลคซีไกลโพ้นหรือว่าเพื่อนร่วมงานคนหนึ่งของคุณตรวจสอบในสัปดาห์ที่ผ่านมาหรือไม่ว่าคุณจะเขียนวันนี้รหัสมรดกเป็นรหัสโดยไม่มีการทดสอบ
ถามตัวเองว่า: ทำไมเราถึงเขียนการทดสอบหน่วย เห็นได้ชัดว่า Going Green หมายถึงจุดจบเป้าหมายสุดท้ายคือการพิสูจน์หรือพิสูจน์ว่าไม่ถูกต้องเกี่ยวกับรหัสที่อยู่ระหว่างการทดสอบ
สมมติว่าคุณมีวิธีที่คำนวณสแควร์รูทของจำนวนจุดลอยตัว ใน Java อินเตอร์เฟสจะนิยามเป็น:
public double squareRoot(double number);
ไม่สำคัญว่าคุณจะเขียนการนำไปใช้หรือว่ามีคนอื่นทำคุณต้องการยืนยันคุณสมบัติบางอย่างของ squareRoot:
- สามารถคืนค่ารูตแบบง่ายๆเช่น sqrt (4.0)
- สามารถหารูทจริงเช่น sqrt (2.0) ได้อย่างแม่นยำ
- พบว่า sqrt (0.0) เท่ากับ 0.0
- มันจะโยน IllegalArgumentException เมื่อป้อนจำนวนลบเช่นบน sqrt (-1.0)
ดังนั้นคุณเริ่มเขียนสิ่งเหล่านี้เป็นแบบทดสอบรายบุคคล:
@Test
public void canFindSimpleRoot() {
assertEquals(2, squareRoot(4), epsilon);
}
โอ๊ะการทดสอบนี้ล้มเหลวแล้ว:
java.lang.AssertionError: Use assertEquals(expected, actual, delta) to compare floating-point numbers
คุณลืมเลขคณิตจุดลอยตัว ตกลงคุณแนะนำdouble epsilon=0.01
และไปที่:
@Test
public void canFindSimpleRootToEpsilonPrecision() {
assertEquals(2, squareRoot(4), epsilon);
}
และเพิ่มการทดสอบอื่น ๆ : ในที่สุด
@Test
@ExpectedException(IllegalArgumentException.class)
public void throwsExceptionOnNegativeInput() {
assertEquals(-1, squareRoot(-1), epsilon);
}
และอุ๊ปส์อีกครั้ง:
java.lang.AssertionError: expected:<-1.0> but was:<NaN>
คุณควรทดสอบ:
@Test
public void returnsNaNOnNegativeInput() {
assertEquals(Double.NaN, squareRoot(-1), epsilon);
}
พวกเราทำอะไรที่นี่? เราเริ่มด้วยการตั้งสมมติฐานบางอย่างเกี่ยวกับวิธีที่วิธีการทำงานและพบว่าไม่ใช่ทั้งหมดที่เป็นจริง จากนั้นเราสร้างชุดการทดสอบสีเขียวเพื่อเขียนหลักฐานที่แสดงว่าวิธีการทำงานเป็นไปตามสมมติฐานที่เราแก้ไข ตอนนี้ลูกค้าของรหัสนี้สามารถพึ่งพาพฤติกรรมนี้ หากมีใครบางคนแลกเปลี่ยนการใช้งานจริงของ squareRoot กับสิ่งอื่นตัวอย่างเช่นสิ่งที่ทำให้เกิดข้อยกเว้นจริงๆแทนที่จะกลับมาเป็น NaN การทดสอบของเราจะจับทันที
ตัวอย่างนี้เล็กน้อย แต่บ่อยครั้งที่คุณรับรหัสขนาดใหญ่ซึ่งไม่ชัดเจนว่ามันทำอะไร ในกรณีนี้มันเป็นเรื่องปกติที่จะวางสายรัดทดสอบไว้รอบ ๆ รหัส เริ่มต้นด้วยสมมติฐานพื้นฐานบางประการเกี่ยวกับวิธีการทำงานของโค้ดเขียนการทดสอบหน่วยสำหรับพวกเขาทดสอบ ถ้าสีเขียวดีเขียนข้อสอบเพิ่มเติม ถ้าสีแดงตอนนี้คุณมีการยืนยันที่ล้มเหลวที่คุณสามารถถือกับสเป็ค อาจมีข้อผิดพลาดในรหัสดั้งเดิม ข้อมูลจำเพาะอาจไม่ชัดเจนเกี่ยวกับอินพุตเฉพาะนี้ บางทีคุณอาจไม่มีสเป็ค ในกรณีนั้นให้เขียนการทดสอบอีกครั้งเพื่อบันทึกการทำงานที่ไม่คาดคิด
@Test
public void throwsNoExceptionOnNegativeInput() {
assertNotNull(squareRoot(-1)); // Shouldn't this fail?
}
เมื่อเวลาผ่านไปคุณจะพบกับชุดทดสอบที่บันทึกว่ารหัสทำงานอย่างไรและกลายเป็นข้อมูลจำเพาะที่เข้ารหัส หากคุณต้องการเปลี่ยนรหัสดั้งเดิมหรือแทนที่ด้วยรหัสอื่นคุณมีสายรัดทดสอบเพื่อตรวจสอบว่ารหัสใหม่ทำงานเหมือนเดิมหรือรหัสใหม่ทำงานแตกต่างกันตามวิธีที่คาดหวังและควบคุม (ตัวอย่างเช่นจริง ๆ แล้ว แก้ไขข้อบกพร่องที่คุณคาดว่าจะแก้ไข) ในความเป็นจริงการมีบังเหียนที่ไม่สมบูรณ์นั้นเกือบจะดีกว่าการไม่มีบังเหียนเลย การมีสายรัดหมายความว่าคุณสามารถเขียนรหัสลูกค้าของคุณได้อย่างง่ายดายมากขึ้นคุณรู้ได้ว่าจะคาดหวังอะไรได้บ้างเมื่อคุณเปลี่ยนอะไรบางอย่าง
คุณควรพยายามออกจากความคิดที่คุณต้องเขียนการทดสอบหน่วยเพียงเพราะคุณต้องกรอกข้อมูลลงในช่องบังคับในแบบฟอร์ม และคุณไม่ควรเขียนบททดสอบเพื่อทำให้เส้นสีแดงเป็นสีเขียว การทดสอบหน่วยไม่ใช่ศัตรูของคุณการทดสอบยูนิตเป็นเพื่อนของคุณ