2012-01-07 30 views
6

Tôi muốn tạo mã đơn vị có thể kiểm tra để loại bỏ các cuộc gọi đến các lớp .Net System.IO, vì vậy tôi có thể thực sự kiểm tra đơn vị thay vì tùy thuộc vào hệ thống tệp. Tôi đang sử dụng các lớp học SystemWrapper để quấn quanh các lớp học BCL.Làm cách nào để tạo mã có thể kiểm tra bằng các lớp .Net IO?

Tôi đang cố gắng lấy ví dụ đơn giản để xem liệu tệp có tồn tại hay không. Vấn đề tôi đang gặp là việc tiêm phụ thuộc vào lớp không hoạt động vì việc khởi tạo phụ thuộc (thông qua StructureMap) đòi hỏi phải biết tham số constructor cần truyền, cái nào sẽ không có sẵn tại thời điểm đó, cũng có không có hàm tạo mặc định.

mẫu mã:

// don't want to create dependency here like so 
//IFileInfoWrap fileInfoWrap = new FileInfoWrap(filename); 

// using service locator (anti-pattern?!) since it can't be 
// injected in this class 
var fileInfoWrap = ObjectFactory.GetInstance<IFileInfoWrap>(
    new ExplicitArguments(new Dictionary<string, object> 
    { 
     {"fileName", filename} 
    })); 

Console.WriteLine("File exists? {0}", fileInfoWrap.Exists); 

Những gì tôi không thích là phụ thuộc không được tiêm, ObjectFactory không nên có mặt ở đây (nhưng tôi thấy không có cách nào khác tạo này). Các ExplicitArguments làm cho nó lộn xộn và các đối số-tên là một chuỗi ma thuật.

Đối với tôi để có được điều này để làm việc lớp StructureMap cấu hình cần biết explict mà constructor Tôi muốn sử dụng (tôi chỉ mới bắt đầu với StructureMap vì vậy đây có thể không phải là cách đúng đắn để thiết lập nó):

ObjectFactory.Initialize(x => 
{ 
    x.Scan(scan => 
    { 
     scan.AssembliesFromPath("."); 
     scan.RegisterConcreteTypesAgainstTheFirstInterface(); 
     scan.WithDefaultConventions(); 
    }); 

    // use the correct constructor (string instead of FileInfo) 
    x.SelectConstructor(() => new FileInfoWrap(null as string)); 

    // setting the value of the constructor 
    x.For<IFileInfoWrap>() 
     .Use<FileInfoWrap>() 
     .Ctor<string>("fileName") 
     .Is(@"."); 
}); 

Có ai tìm thấy giải pháp tốt hơn để tạo mã có thể kiểm tra đối với các lớp System.IO không? Tôi biết một phần của vấn đề là trong thiết kế của các lớp System.IO.

+3

SystemWrapper chứa trừu tượng chủ yếu là cực kỳ rò rỉ. Nó sẽ đơn giản hơn và dễ dàng hơn để mô hình hóa IO đối với các luồng, TextWriter, TextReader, vv Các lớp này đã trừu tượng, hoàn toàn loại bỏ sự cần thiết cho SystemWrapper. –

+0

Một phiếu bầu cho các luồng –

+0

Phát hiện của tôi với SystemWrapper là nó có vẻ là một trình bao bọc đẹp mắt với các giao diện, tuy nhiên nó vẫn là một kết thúc chết vì cách các lớp gốc hoạt động. Ví dụ trả về một mảng các đối tượng FileInfo không thể được mô phỏng đúng cách. Cuộn trình bao bọc đơn giản hơn của riêng tôi mà không phải bắt chước các lớp hiện có, trong khi nhiều công việc hơn dẫn đến một giải pháp khả thi IMHO. –

Trả lời

5

Cách tiếp cận tôi đã sử dụng rất thành công là cuộn các loại proxy của riêng mình cho các loại được tìm thấy trong System.IO và các phần khác của FCL. Ví dụ. Tôi muốn phụ thuộc vào System.IO.File. Tôi tạo một thư viện có tên là System.IO.Proxies và thêm một loại bê tông File và một giao diện IFile. Giao diện IFile cho thấy các thành viên tương đương với tất cả các thành viên mà tôi yêu cầu từ System.IO.File và loại cụ thể triển khai các thành viên đó bằng cách không thực hiện gì ngoài chuyển tiếp cuộc gọi đến System.IO.File. System.IO.Proxies bị loại trừ khỏi kiểm tra đơn vị và phạm vi mã. Trong hội đồng tiêu thụ của tôi, tôi chỉ nhận một sự phụ thuộc vào số System.IO.Proxies và đặc biệt, tôi chỉ phụ thuộc vào IFile. Bằng cách này tôi có thể giả lập sự phụ thuộc này một cách dễ dàng và đạt được mức độ bao phủ 100% mã cho hội đồng tiêu thụ của tôi.

(Lưu ý rằng đây là một phiên bản phù của tôi more general answer cho một câu hỏi trước.)

+0

Vâng, đó là cách tôi kết thúc. Người ta có thể ủy quyền cuộc gọi đến, ví dụ: System.IO.FileInfo đến một lớp riêng biệt. Việc truyền proxy của riêng bạn yêu cầu tạo proxy cho mỗi lớp có thể là một số công việc, tất nhiên nó có thể phát triển cùng với chức năng cần thiết từ lớp BCL. Ngoài ra khi các loại khác (FileInfo) được trả về, tất cả các thuộc tính bắt buộc phải được tạo trong proxy (Tên, Họ tên, Độ dài). Người ta sẽ nghĩ rằng vấn đề này sẽ được 'giải quyết' đã tránh proxy cho tất cả mọi người. –

+0

Sử dụng cùng một cách tiếp cận khá thành công. Thông thường, bạn không cần tất cả các phương thức/thuộc tính/sự kiện của một lớp như _File_. Và đối với số ít bạn cần nó thực sự dễ dàng để viết bao hàm như vậy. –

Các vấn đề liên quan