2012-02-15 42 views
5

Ngăn xếp công nghệ: .NET 4, C#, NUnitTDD: Có hợp lý để thử nghiệm tích hợp, nhưng không có thử nghiệm đơn vị?

Tôi đang cố gắng áp dụng phát triển hướng thử nghiệm cho dự án mới thực hiện xử lý hình ảnh. Tôi có một lớp cơ sở có chứa các phương thức I/O và các lớp con được chia sẻ thực hiện các thuật toán xử lý cụ thể khác nhau. Như tôi đã hiểu, các bài kiểm tra đơn vị không chạm vào hệ thống tệp hoặc các đối tượng khác và hành vi mô phỏng nơi xảy ra. Lớp cơ sở của tôi chỉ chứa các trình truy cập đơn giản và các cuộc gọi I/O hệ thống tập tin đơn giản.

public class BaseFile 
{ 
    public String Path { get; set; } 

    public BaseFile() 
    { 
     Path = String.Empty; 
    } 

    public BaseFile(String path) 
    { 
     if (!File.Exists(path)) 
     { 
      throw new FileNotFoundException("File not found.", path); 
     } 

     Path = path; 
    } 
} 

Có giá trị nào trong thử nghiệm các phương pháp này không? Nếu vậy, làm thế nào tôi có thể tóm tắt các cuộc gọi đến hệ thống tập tin?

Câu hỏi khác của tôi là cách kiểm tra lớp con cụ thể cho loại tệp hình ảnh (~ 200 MB). Tôi đã tìm kiếm trang web và tìm thấy similarquestions, nhưng không ai xử lý các kích thước tệp mà tôi đang làm việc với dự án này. Là nó hợp lý cho một lớp học để có các bài kiểm tra tích hợp (sử dụng một "tập tin vàng"), nhưng không có bài kiểm tra đơn vị? Làm thế nào tôi có thể thực hiện đúng các phương pháp TDD và đầu tiên viết một thử nghiệm thất bại trong trường hợp này?

+4

Nếu TDD khó áp dụng hoặc không đủ, không áp dụng. Nó không phải là viên đạn bạc. – CharlesB

+1

@CharlesB, tôi đồng ý. Thật không may rằng tình cảm thường được sử dụng như là lý do cho việc không sử dụng TDD khi nó thực sự đúng và thuận lợi để làm như vậy. Đôi khi có đường cong lớn hoặc rất nhiều nền tảng để làm nhưng điều này thường trả hết. –

+1

@CharlesB Không chắc chắn tôi đồng ý với điều đó. Vấn đề là sau đó lớp học này mà một số công việc không được thử nghiệm, và do đó sự tự tin của bạn để thay đổi nó được giảm bớt. Vấn đề là nó không dễ dàng giả lập các phương thức tĩnh trong System.IO, nhưng điều đó không có nghĩa là từ bỏ việc kiểm thử, nó chỉ có nghĩa là bạn cần làm một ít công việc để làm cho chúng có thể kiểm thử được. Đây là lý do tại sao MS giới thiệu System.Web.HttpContextBase, để giải quyết các vấn đề không dễ dàng có thể giả lập một HttpContext. Chúng tôi không cần phải kiểm tra httpContext, chỉ cần mã của chúng tôi tương tác chính xác với nó. – Andy

Trả lời

4

Trong câu trả lời cho câu hỏi đầu tiên của bạn, có giá trị trong việc thử nghiệm các phương pháp này. Tôi đã xuất bản một thư viện tạo điều kiện thực hiện chính xác mà không thực sự nhấn vào hệ thống tệp: https://bitbucket.org/mylesmcdonnell/mpm.io/wiki/Home

Câu trả lời thứ hai của bạn là cần thiết. Tôi nghi ngờ bạn có thể cần phải thực hiện tương tự tiếp cận với lib ở trên. cụ thể là; xác định giao diện, xác định proxy cho bê tông, xác định nhà máy để trả về proxy hoặc giả lập.

+0

Cảm ơn bạn đã đăng mã nguồn này. Tôi đang đánh dấu bài đăng của bạn là câu trả lời vì bạn đã cung cấp giải pháp chung tốt nhất. – Noren

3

Làm cách nào tôi có thể theo đúng phương pháp TDD và trước tiên viết bài kiểm tra lỗi trong trường hợp này?

Dễ dàng! Bạn giả lập hệ thống tập tin :)

Điều này nghe có vẻ như rất nhiều công việc, nhưng thông thường bạn chỉ cần thực hiện một vài phương pháp và mở rộng khi cần thiết. Trong trường hợp trên ... bạn chỉ cần một.

public interface IFileStore 
{ 
    Boolean FileExists(String path); 
} 

Ý tưởng là ủy quyền tác phẩm của bạn phía sau giao diện và tạo triển khai cụ thể để thực hiện việc nâng hạng nặng. Về cơ bản là Adapter pattern.

Tôi thậm chí không phản đối "DI của người nghèo" cho loại điều này vì bạn có thể triển khai vùng chứa sau nếu ứng dụng của bạn gọi. Trong trường hợp này ... có lẽ bạn sẽ luôn sử dụng hệ thống tệp thực.

public class BaseFile 
{ 
    private IFileStore _fileStore 
    public IFileStore FileStore 
    { 
     get 
     { 
      return _fileStore ?? (_fileStore = new ConcreteFileStore()); 
     } 
     set 
     { 
      _fileStore = value; 
     } 
    } 

    //SNIP... 
} 

Bây giờ bạn có thể triển khai có thể kiểm tra và bạn sẽ không phải dựa vào bất kỳ tệp "Vàng" nào.

+0

Cảm ơn bạn đã đăng bài. Bây giờ, tôi sẽ triển khai giải pháp của bạn cho đến khi tôi cần thêm các cuộc gọi System.IO, tại thời điểm đó tôi sẽ sử dụng mã của Myles. – Noren

0

Kiểm tra tích hợp có giá trị riêng. Nếu bạn giả lập hệ thống tệp, như được giải thích trong câu trả lời của Joshs, bạn thực sự không biết chắc chắn rằng mã của bạn sẽ thực sự chạy trong sản xuất hay không. Hệ thống tệp có nhiều hợp đồng ẩn không quan trọng để giả lập. Nếu giả/giả của bạn cho thấy hành vi hơi khác nhau, mã của bạn có thể bắt đầu dựa vào nó mà bạn không biết.

Chỉ thử nghiệm tích hợp mới có thể cho biết một số điều chắc chắn. (Kiểm thử tích hợp cũng có nhược điểm!).

+0

Chính xác. Tôi không ngụ ý rằng bạn * không nên * làm thử nghiệm tích hợp. Thay vào đó, TDD vẫn có thể được thực hiện ngay cả trên những thứ mà chúng ta thường không xem xét như Hệ thống tệp. – Josh

+0

Tôi không có nghĩa là làm giảm giá trị giải thích của bạn. Tôi đã tham khảo nó bởi vì nó tốt. – usr

1

Có giá trị trong việc thử nghiệm những phương pháp

khi nó có vẻ như việc làm thêm để trục lợi tầm thường ngay bây giờ, thêm các xét nghiệm như BaseFile nên ném FileNotFoundException khi tập tin không tồn tại hoàn thành ít nhất hai mục tiêu :

xác định danh sách các hành vi mong đợi

người mới đến dự án có thể xem lại tên thử nghiệm để xác định như thế nào c của bạn lasses được dự định để hoạt động. Họ sẽ biết những gì mong đợi trong mỗi tình huống - một ngoại lệ, một null, một kết quả mặc định, v.v.

Nó cũng buộc bạn suy nghĩ và xác định bằng tiếng Anh đơn giản. ném vào điều kiện và ngoại lệ ở đây và ở đó. Điều này sẽ dẫn đến một triết lý rất nhất quán được áp dụng trong toàn bộ dự án của bạn.

Grow một bộ kiểm tra hồi quy tự động

Hãy xem xét rằng ai đó nhìn thấy một số mã ném một ngoại lệ trong một điều kiện cụ thể, nhưng họ nghĩ rằng đó là khôn ngoan để làm cái gì khác (ăn lỗi, nhưng thêm một mới Tài sản IsValid để người tiêu dùng có thể biết liệu việc xây dựng/khởi tạo có thành công hay không). Nếu họ thực hiện một thay đổi như vậy, bài kiểm tra sẽ rất nhanh chóng thu hút sự chú ý đến sự thay đổi. Có một quyết định có ý thức và có chủ ý đằng sau cách mọi thứ, và mọi người có thể đã phát triển dựa vào hành vi hiện tại - thay đổi này cần thảo luận thêm trước khi nó có thể được chấp nhận.

Đối với phần thứ hai của câu hỏi của bạn, tôi nghĩ rằng Josh và Myles đã cung cấp cả hai lời khuyên âm thanh rồi.

+0

Bạn đã đạt được điểm tốt. Tôi tin rằng tôi sẽ để lại trong các bài kiểm tra cho những phương pháp đơn giản này. – Noren

1

Việc bỏ qua các cuộc gọi hệ thống tệp đơn giản bằng giao diện có vẻ như quá mức cần thiết. Tương tự như vậy đối với những thứ như chế nhạo thời gian hiện tại bằng cách sử dụng ITimeService. Tôi có xu hướng sử dụng Func hoặc Hành động vì nó đơn giản hơn nhiều:

public static Func<string, bool> FileExists = System.IO.File.Exists; 
public static Func<DateTime> GetCurrentTime =() => DateTime.Now; 

Vì chúng là công khai, tôi có thể dễ dàng thử nghiệm đơn vị. Mã đơn giản, không cần phải tiêm các giao diện khác nhau cho những thứ đơn giản. Đối với luồng, tôi thường sử dụng MemoryStream trong tets đơn vị.

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