คำถามของคุณทำให้หนึ่งในส่วนที่ยากที่สุดของการทดสอบสำหรับนักพัฒนาเพิ่งเริ่มทำ:
"ฉันจะทดสอบอะไรดี
ตัวอย่างของคุณไม่น่าสนใจมากนักเพราะมันแค่เรียก API บางอย่างเข้าด้วยกันดังนั้นถ้าคุณเขียนการทดสอบหน่วยคุณก็จะลงเอยด้วยการยืนยันวิธีการที่ถูกเรียก การทดสอบเช่นนี้จะทำให้รายละเอียดการใช้งานของคุณใกล้เคียงกับการทดสอบ สิ่งนี้ไม่ดีเพราะตอนนี้คุณต้องเปลี่ยนการทดสอบทุกครั้งที่คุณเปลี่ยนรายละเอียดการใช้งานของวิธีการของคุณเพราะการเปลี่ยนแปลงรายละเอียดการใช้งานทำให้การทดสอบของคุณแตก!
การมีการทดสอบที่ไม่ดีนั้นเลวร้ายยิ่งกว่าการไม่มีการทดสอบเลย
ในตัวอย่างของคุณ:
void DoIt(IZipper zipper, IFileSystem fileSystem, IDllRunner runner)
{
string path = zipper.Unzip(theZipFile);
IFakeFile file = fileSystem.Open(path);
runner.Run(file);
}
ในขณะที่คุณสามารถผ่านเป็น mocks ไม่มีเหตุผลในวิธีการทดสอบ หากคุณพยายามทดสอบหน่วยนี้อาจมีลักษณะดังนี้:
// Assuming that zipper, fileSystem, and runner are mocks
void testDoIt()
{
// mock behavior of the mock objects
when(zipper.Unzip(any(File.class)).thenReturn("some path");
when(fileSystem.Open("some path")).thenReturn(mock(IFakeFile.class));
// run the test
someObject.DoIt(zipper, fileSystem, runner);
// verify things were called
verify(zipper).Unzip(any(File.class));
verify(fileSystem).Open("some path"));
verify(runner).Run(file);
}
ขอแสดงความยินดีโดยทั่วไปคุณคัดลอกรายละเอียดการติดตั้งDoIt()
วิธีการของคุณไปใช้ในการทดสอบ มีความสุข
เมื่อคุณเขียนทดสอบคุณต้องการที่จะทดสอบอะไรและไม่อย่างไร
ดูการทดสอบกล่องดำเพิ่มเติม
สิ่งที่เป็นชื่อของวิธีการของคุณ (หรืออย่างน้อยก็ควรจะเป็น) วิธีมีทุกรายละเอียดการดำเนินงานเล็ก ๆ น้อย ๆ ที่อาศัยอยู่ภายในวิธีการของคุณ การทดสอบที่ดีช่วยให้คุณสามารถสลับออกวิธีโดยไม่ทำลายสิ่ง
คิดแบบนี้ถามตัวเอง:
"ถ้าฉันเปลี่ยนรายละเอียดการใช้งานของวิธีนี้ (โดยไม่ต้องแก้ไขสัญญาสาธารณะ) มันจะทำลายการทดสอบของฉันหรือไม่"
ถ้าคำตอบคือใช่คุณกำลังทดสอบวิธีและไม่อะไร
ในการตอบคำถามเฉพาะของคุณเกี่ยวกับการทดสอบรหัสด้วยการขึ้นต่อกันของระบบไฟล์สมมติว่าคุณมีสิ่งที่น่าสนใจเกิดขึ้นกับไฟล์และคุณต้องการบันทึกเนื้อหาที่เข้ารหัส Base64 ของ a byte[]
ไปยังไฟล์ คุณสามารถใช้สตรีมสำหรับสิ่งนี้เพื่อทดสอบว่าโค้ดของคุณทำในสิ่งที่ถูกต้องโดยไม่ต้องตรวจสอบวิธีการใช้งาน ตัวอย่างหนึ่งอาจเป็นดังนี้ (ใน Java):
interface StreamFactory {
OutputStream outStream();
InputStream inStream();
}
class Base64FileWriter {
public void write(byte[] contents, StreamFactory streamFactory) {
OutputStream outputStream = streamFactory.outStream();
outputStream.write(Base64.encodeBase64(contents));
}
}
@Test
public void save_shouldBase64EncodeContents() {
OutputStream outputStream = new ByteArrayOutputStream();
StreamFactory streamFactory = mock(StreamFactory.class);
when(streamFactory.outStream()).thenReturn(outputStream);
// Run the method under test
Base64FileWriter fileWriter = new Base64FileWriter();
fileWriter.write("Man".getBytes(), streamFactory);
// Assert we saved the base64 encoded contents
assertThat(outputStream.toString()).isEqualTo("TWFu");
}
การทดสอบใช้ByteArrayOutputStream
แต่ในการประยุกต์ใช้ (ใช้ฉีดพึ่งพา) เดอะ StreamFactory จริง (บางทีเรียกว่า FileStreamFactory) จะกลับมาFileOutputStream
จากและเขียนไปยังoutputStream()
File
สิ่งที่น่าสนใจเกี่ยวกับwrite
วิธีการที่นี่คือมันเขียนเนื้อหาออก Base64 ที่เข้ารหัสดังนั้นนั่นคือสิ่งที่เราทดสอบ สำหรับคุณDoIt()
วิธีนี้จะได้รับการทดสอบอย่างเหมาะสมกับการทดสอบบูรณาการ