มีห้องสมุดหรือวิธีการจำลองระบบไฟล์ใน C # เพื่อเขียนการทดสอบหน่วยหรือไม่? ในกรณีปัจจุบันของฉันฉันมีวิธีการตรวจสอบว่ามีไฟล์บางไฟล์อยู่และอ่านวันที่สร้าง ฉันอาจต้องการมากกว่านั้นในอนาคต
มีห้องสมุดหรือวิธีการจำลองระบบไฟล์ใน C # เพื่อเขียนการทดสอบหน่วยหรือไม่? ในกรณีปัจจุบันของฉันฉันมีวิธีการตรวจสอบว่ามีไฟล์บางไฟล์อยู่และอ่านวันที่สร้าง ฉันอาจต้องการมากกว่านั้นในอนาคต
คำตอบ:
แก้ไข: System.IO.Abstractions
การติดตั้งแพคเกจ
แพคเกจนี้ไม่ได้อยู่เมื่อคำตอบนี้เป็นที่ยอมรับเดิม คำตอบดั้งเดิมมีไว้สำหรับบริบททางประวัติศาสตร์ด้านล่าง:
คุณสามารถทำได้โดยสร้างอินเทอร์เฟซ:
interface IFileSystem { bool FileExists(string fileName); DateTime GetCreationDate(string fileName); }
และการสร้างการใช้งาน 'ของจริง' ซึ่งใช้ System.IO.File.Exists () ฯลฯ จากนั้นคุณสามารถจำลองอินเตอร์เฟสนี้โดยใช้กรอบการทำงานที่เยาะเย้ย ผมขอแนะนำขั้นต่ำ
แก้ไข: ใครบางคนทำแบบนี้และโพสต์ออนไลน์กรุณาที่นี่
ฉันใช้วิธีนี้เพื่อเยาะเย้ย DateTime.UtcNow ในอินเทอร์เฟซ IClock (มีประโยชน์จริง ๆ สำหรับการทดสอบของเราเพื่อให้สามารถควบคุมการไหลของเวลา!)
อีกวิธีหนึ่งอาจใช้TypeMockซึ่งจะช่วยให้คุณสามารถสกัดกั้นการโทรไปยังคลาสต่างๆ สิ่งนี้จะมีค่าใช้จ่ายและจะต้องติดตั้งบนพีซีทั้งหมดของทีมของคุณและเซิร์ฟเวอร์บิลด์ของคุณเพื่อให้ทำงานได้เช่นกันดูเหมือนว่ามันจะไม่ทำงานสำหรับ System.IO.File เนื่องจากมันไม่สามารถ stub mscorlibได้
คุณสามารถยอมรับได้ว่าวิธีการบางอย่างนั้นไม่ใช่หน่วยที่ทดสอบได้และทดสอบในชุดการรวมระบบ / ทดสอบที่ทำงานช้าแยกต่างหาก
ไลบรารีจินตภาพนี้มีอยู่ในขณะนี้มีแพ็คเกจ NuGet สำหรับSystem.IO.Abstractionsซึ่งย่อส่วนเนมสเปซ System.IO
นอกจากนี้ยังมีชุดของผู้ช่วยทดสอบ System.IO.Abstractions การทดสอบผู้ช่วยซึ่ง - ในขณะที่เขียน - จะดำเนินการเพียงบางส่วนเท่านั้น แต่เป็นจุดเริ่มต้นที่ดีมาก
คุณอาจจะต้องสร้างสัญญาเพื่อกำหนดสิ่งที่คุณต้องการจากระบบไฟล์แล้วเขียนเสื้อคลุมรอบฟังก์ชันเหล่านั้น ณ จุดนี้คุณจะสามารถเยาะเย้ยหรือเริ่มต้นการนำไปใช้งาน
ตัวอย่าง:
interface IFileWrapper { bool Exists(String filePath); }
class FileWrapper: IFileWrapper
{
bool Exists(String filePath) { return File.Exists(filePath); }
}
class FileWrapperStub: IFileWrapper
{
bool Exists(String filePath)
{ return (filePath == @"C:\myfilerocks.txt"); }
}
คำแนะนำของฉันคือการใช้http://systemwrapper.codeplex.com/ เนื่องจากมีการห่อสำหรับประเภทที่ใช้ส่วนใหญ่ใน System namespace
ฉันเจอวิธีแก้ไขปัญหาต่อไปนี้:
ฉันใช้วิธีทั้งหมดข้างต้นขึ้นอยู่กับสิ่งที่ฉันเขียน แต่ส่วนใหญ่ฉันคิดว่านามธรรมเป็นสิ่งที่ผิดเมื่อฉันเขียนการทดสอบหน่วยที่ตี IO
โดยใช้System.IO.AbstractionsและSystem.IO.Abstractions.TestingHelpersเช่นนั้น:
public class ManageFile {
private readonly IFileSystem _fileSystem;
public ManageFile(IFileSystem fileSystem){
_fileSystem = fileSystem;
}
public bool FileExists(string filePath){}
if(_fileSystem.File.Exists(filePath){
return true;
}
return false;
}
}
ในคลาสทดสอบของคุณคุณใช้ MockFileSystem () เพื่อจำลองไฟล์และคุณได้ติดตั้ง ManageFile เช่น:
var mockFileSysteme = new MockFileSystem();
var mockFileData = new MockFileData("File content");
mockFileSysteme.AddFile(mockFilePath, mockFileData );
var manageFile = new ManageFile(mockFileSysteme);
คุณสามารถทำได้โดยใช้Microsoft Fakesโดยไม่จำเป็นต้องเปลี่ยน codebase ของคุณเพราะมันถูกตรึงไว้แล้ว
ขั้นแรกสร้างแอสเซมบลีปลอมสำหรับ System.dll - หรือแพคเกจอื่น ๆ จากนั้นจำลองที่คาดว่าจะได้รับผลตอบแทนเช่นเดียวกับใน:
using Microsoft.QualityTools.Testing.Fakes;
...
using (ShimsContext.Create())
{
System.IO.Fakes.ShimFile.ExistsString = (p) => true;
System.IO.Fakes.ShimFile.ReadAllTextString = (p) => "your file content";
//Your methods to test
}
มันจะเป็นการยากที่จะเยาะเย้ยระบบไฟล์ในการทดสอบเนื่องจาก API ไฟล์. NET นั้นไม่ได้ขึ้นอยู่กับอินเทอร์เฟซหรือคลาสที่สามารถขยายได้ที่อาจถูกเยาะเย้ย
อย่างไรก็ตามหากคุณมีเลเยอร์การทำงานของคุณเองเพื่อเข้าถึงระบบไฟล์คุณสามารถเยาะเย้ยว่าในการทดสอบหน่วย
ทางเลือกอื่นสำหรับการเยาะเย้ยพิจารณาเพียงแค่สร้างโฟลเดอร์และไฟล์ที่คุณต้องการเป็นส่วนหนึ่งของการตั้งค่าการทดสอบและลบทิ้งในวิธีการฉีกขาด
ฉันไม่แน่ใจว่าคุณจะล้อเลียนระบบไฟล์อย่างไร สิ่งที่คุณสามารถทำได้คือเขียนการตั้งค่าการติดตั้งการทดสอบที่สร้างโฟลเดอร์ ฯลฯ ด้วยโครงสร้างที่จำเป็นสำหรับการทดสอบ เมธอด teardown จะทำความสะอาดหลังจากการทดสอบทำงาน
แก้ไขเพื่อเพิ่ม: ในการคิดเกี่ยวกับสิ่งนี้อีกเล็กน้อยฉันไม่คิดว่าคุณต้องการจำลองระบบไฟล์เพื่อทดสอบวิธีการประเภทนี้ หากคุณจำลองระบบไฟล์ให้คืนค่าจริงหากมีไฟล์บางไฟล์อยู่และใช้วิธีนั้นในการทดสอบวิธีการตรวจสอบว่าไฟล์นั้นมีอยู่หรือไม่แสดงว่าคุณไม่ได้ทดสอบอะไรมากมาย การเยาะเย้ยระบบไฟล์จะมีประโยชน์คือถ้าคุณต้องการทดสอบวิธีที่มีการพึ่งพาระบบไฟล์ แต่กิจกรรมของระบบไฟล์นั้นไม่ได้เป็นส่วนหนึ่งของวิธีการทดสอบ
หากต้องการตอบคำถามเฉพาะของคุณ: ไม่ไม่มีห้องสมุดที่จะอนุญาตให้คุณจำลองการโทร I / O ของไฟล์ (ที่ฉันรู้) ซึ่งหมายความว่าหน่วย "ถูกต้อง" การทดสอบประเภทของคุณจะต้องให้คุณพิจารณาข้อ จำกัด นี้เมื่อคุณกำหนดประเภทของคุณ
หมายเหตุด้านด่วนเกี่ยวกับวิธีที่ฉันกำหนดการทดสอบหน่วย "เหมาะสม" ฉันเชื่อว่าการทดสอบหน่วยควรยืนยันว่าคุณได้รับผลลัพธ์ที่คาดหวัง (ไม่ว่าจะเป็นข้อยกเว้นการเรียกใช้เมธอดและอื่น ๆ ) ที่ได้รับจากอินพุตที่ทราบ สิ่งนี้ช่วยให้คุณสามารถตั้งค่าเงื่อนไขการทดสอบหน่วยของคุณเป็นชุดอินพุตและ / หรือสถานะอินพุต วิธีที่ดีที่สุดที่ฉันได้พบคือใช้บริการที่อิงกับอินเตอร์เฟสและการฉีดขึ้นต่อกันเพื่อให้แต่ละความรับผิดชอบภายนอกกับประเภทมีให้ผ่านทางอินเตอร์เฟสที่ส่งผ่านคอนสตรัคเตอร์หรือคุณสมบัติ
ดังนั้นเมื่อนึกถึงสิ่งนี้ในคำถามของคุณ ฉันล้อเลียนระบบไฟล์โดยการสร้างIFileSystemService
ส่วนต่อประสานกับการFileSystemService
ใช้งานที่เป็นเพียงส่วนหน้าของวิธีการระบบไฟล์ mscorlib รหัสของฉันใช้IFileSystemService
มากกว่าประเภท mscorlib สิ่งนี้ทำให้ฉันสามารถเสียบมาตรฐานของฉันFileSystemService
เมื่อแอปพลิเคชันทำงานหรือจำลองการIFileSystemService
ทดสอบหน่วยของฉัน รหัสแอปพลิเคชันเหมือนกันโดยไม่คำนึงถึงวิธีการเรียกใช้ แต่โครงสร้างพื้นฐานที่สำคัญช่วยให้สามารถทดสอบรหัสนั้นได้ง่าย
ฉันจะยอมรับว่ามันเป็นความเจ็บปวดที่จะใช้ wrapper รอบ ๆ วัตถุระบบไฟล์ mscorlib แต่ในสถานการณ์ที่เฉพาะเจาะจงเหล่านี้มันคุ้มค่ากับการทำงานพิเศษเนื่องจากการทดสอบกลายเป็นเรื่องง่ายและน่าเชื่อถือมากขึ้น
การสร้างส่วนต่อประสานและการเยาะเย้ยมันสำหรับการทดสอบเป็นวิธีที่สะอาดที่สุด อย่างไรก็ตามในฐานะที่เป็นอีกทางเลือกหนึ่งคุณสามารถดูกรอบMicrosoft Moles
วิธีแก้ปัญหาทั่วไปคือการใช้ API ระบบไฟล์นามธรรม (เช่นApache Commons VFSสำหรับ Java): แอปพลิเคชันตรรกะทั้งหมดใช้ API และการทดสอบหน่วยสามารถจำลองระบบไฟล์จริงด้วยการใช้งานสตับ (การจำลองในหน่วยความจำหรืออะไรทำนองนั้น)
สำหรับ C # มี API ที่คล้ายกัน: NI.Vfsซึ่งคล้ายกับ Apache VFS V1 มาก มันมีการใช้งานเริ่มต้นทั้งสำหรับระบบไฟล์ในท้องถิ่นและระบบไฟล์ในหน่วยความจำ (ล่าสุดสามารถใช้ในการทดสอบหน่วยจากกล่อง)
ขณะนี้เราใช้เอ็นจิ้นข้อมูลที่เป็นกรรมสิทธิ์และ API ไม่ได้ถูกเปิดเผยเป็นอินเทอร์เฟซดังนั้นเราจึงแทบจะไม่สามารถทดสอบรหัสการเข้าถึงข้อมูลของเราได้ จากนั้นฉันก็ใช้วิธีของแมทและโจเซฟเช่นกัน
ฉันจะตอบสนองด้วย Jamie Ide อย่าพยายามเยาะเย้ยสิ่งที่คุณไม่ได้เขียน จะมีลักษณะของการพึ่งพาทั้งหมดที่คุณไม่รู้เกี่ยวกับ - ชั้นเรียนที่ปิดสนิทไม่ใช่วิธีเสมือนจริง ฯลฯ
อีกวิธีหนึ่งคือการห่อวิธีการเสริมด้วยสิ่งที่เยาะเย้ย เช่นสร้างคลาสที่เรียกว่า FileWrapper ที่อนุญาตให้เข้าถึงวิธีการของไฟล์ แต่เป็นสิ่งที่คุณสามารถเยาะเย้ยได้