2012-03-02 6 views
10

Tôi hiện đang cố gắng tìm hiểu kiểm tra đơn vị thích hợp. Vì vậy, bây giờ tôi đang cố gắng để viết đơn vị kiểm tra cho một lớp học nên bản đồ dữ liệu từ một XML-File cho các đối tượng thích hợp. Tất nhiên tất cả các chức năng của lớp phụ thuộc vào sự tồn tại của tệp XML tương ứng. Tệp XML được tải trong hàm tạo của lớp.Làm thế nào để đơn vị kiểm tra một lớp học mà cần một tập tin cụ thể để có mặt

Tôi đang sử dụng C# với NUnit. Cho đến nay tôi đã có hai bài kiểm tra:

[Test] 
public void ShouldAllowInstanceToBeCreatedWhenXMLFileIsPresent() 
{ 
    if (File.Exists(SettingsReader.XML_SETTINGS_PATH)) 
    { 
     SettingsReader settingsReader = new SettingsReader(); 
     Assert.AreNotEqual(null, settingsReader); 
    } 
} 

[Test] 
[ExpectedException("Telekanzlei.Clientmanager.XMLDataLayer.XMLFileNotFoundException")] 
public void ShouldThrowExceptionWhenXMLFileIsNotPresent() 
{ 
    if (!File.Exists(SettingsReader.XML_SETTINGS_PATH)) 
    { 
     SettingsReader settingsReader = new SettingsReader(); 
    } 
     else 
      throw new XMLFileNotFoundException(); 
    } 

Tôi không chắc chắn nếu kiểm tra sự tồn tại của tập tin trong các thử nghiệm là một cách thích hợp để đi, vì vậy bất kỳ đề xuất về những thử nghiệm được hoan nghênh quá. Nhưng câu hỏi của tôi là, làm thế nào để tiến hành các thử nghiệm sau đây. Rõ ràng tất cả các bài kiểm tra sau đây sẽ thất bại, nếu không có tệp XML.

Vì vậy, tôi cho rằng tệp XML là hiện tại, trong khi lưu ý rằng một thử nghiệm không thành công có thể có nghĩa là nó không phải là? Điều đó dường như không đúng với tôi.

Có mẫu chung nào để xử lý sự cố như thế này không?

Thx cho bất kỳ sự giúp đỡ

chỉnh sửa: viết lại bài kiểm tra thứ hai, vì nó đã thất bại nếu tập tin đã thực sự hiện diện ...

edit2: Có thể nó đang giúp cho bạn biết, những gì thực sự SettingsReader làm. Cho đến nay nó trông như thế này:

public class SettingsReader 
{ 
    public static readonly string XML_SETTINGS_PATH = "C:\\Telekanzlei\\Clientmanager_2.0\\Settings.xml"; 

    public XElement RootXElement { get; private set; } 

    public SettingsReader() 
    { 
     if (!File.Exists(XML_SETTINGS_PATH)) 
      throw new XMLFileNotFoundException(); 
     using (var fs = File.OpenRead(XML_SETTINGS_PATH)) 
     { 
      RootXElement = XElement.Load(fs); 
     } 
    } 


} 

Tôi không chắc chắn, nhưng tôi đoán một StreamReader sẽ không phải là con đường để đi ở đây, đúng không?

+3

Cài đặtĐược thiết kế để sử dụng tính năng tiêm phụ thuộc? Âm thanh như một trường hợp tốt cho DI và chế giễu. –

+1

MSTest có [DeploymentItem] cho việc này. Có lẽ NUnit có một cái gì đó như thế? –

Trả lời

14

Vấn đề không phải là với các bài kiểm tra đơn vị của bạn nhưng với thiết kế của lớp. Tôi muốn đề nghị tái cấu trúc lớp để nó không mở tệp mà thay vào đó hoạt động trên luồng. Sau đó, các bài kiểm tra đơn vị của bạn có thể đơn giản thay thế luồng tệp cho luồng bộ nhớ - các mẫu! :)

public class SettingsReader() 
{ 
    public SettingsReader(System.IO.StreamReader reader) 
    { 
     // read contents of stream... 
    } 
} 

// In production code: 
new SettingsReader(new StreamReader(File.Open("settings.xml"))); 

// In unit test: 
new SettingsReader(new StringReader("<settings>dummy settings</settings>")); 

Hãy nhớ rằng, mở tệp và phân tích dữ liệu cài đặt là hai mối quan tâm rất khác nhau.

+0

Tôi vừa nhận ra rằng phương thức XElement.Load đang lấy một luồng làm tham số. Tôi chưa quen với .NET. Nhưng đề xuất của bạn có vẻ như là một cách tiếp cận tốt. Vì vậy, tôi sẽ chia ra rằng trong cho phép nói một lớp SettingsStreamProvider và một lớp SettingsParser và sử dụng tiêm phụ thuộc cho trình phân tích cú pháp? – Tobi

+0

Giá trị nào mà lớp nhà cung cấp luồng thiết lập chỉ có một luồng đơn giản? Tôi nghĩ rằng đó sẽ là một trừu tượng vô nghĩa - KISS :) – MattDavey

+0

Điểm chụp^^ Điều này là mặc dù tôi đang sử dụng SettingsReader nhiều lần trong dự án của tôi, nhưng luôn luôn với cùng một tập tin XML. Tôi sẽ không thích nó nhiều, để tạo ra một dòng mới "bằng tay" mỗi khi tôi sử dụng nó. Đó là lý do tại sao tôi muốn xử lý việc mở luồng trong lớp SettingsReader ở vị trí đầu tiên ... – Tobi

5

Nếu bạn phải đề nghị bạn sử dụng phương thức Thiết lập để sao chép hoặc xác minh rằng tệp tồn tại. Tôi khuyên bạn nên đảm bảo tệp có mặt bằng cách thêm tệp đó vào dự án thử nghiệm và đánh dấu nó là "sao chép luôn" khi bạn nhận được công việc đó không cần phải kiểm tra lại.
Nếu bạn có nhiều thử nghiệm yêu cầu tệp bên ngoài, có lẽ bạn nên sử dụng MsTest - nó có thuộc tính được gọi là DeploymentItem để đảm bảo rằng tệp được sao chép vào cùng một vị trí như thử nghiệm.

3

Hãy xem xét viết lại mã để phụ thuộc có thể được chuyển vào hoặc bằng cách nào đó khác được phân phối cho mã bạn muốn kiểm tra đơn vị.

I.e. vượt qua một cái gì đó như "IMySettingsFileProvider" dụ để constructor SettingsReader nơi IMySettingsFileProvider.SettingsXml trả về một số dòng thiết lập. Bằng cách này bạn có thể giả lập giao diện IMySettingsFileProvider để kiểm tra thay vì yêu cầu tệp có mặt trên đĩa.

+1

Nó sẽ không phải là một chút "quá mức"? Tệp XML chỉ được sử dụng bởi lớp đơn này. Tạo một lớp + Giao diện chỉ để tải tập tin? – Tobi

+1

Đồng ý. Tôi không hiểu tại sao mọi người lại thêm quá nhiều phức tạp với chế nhạo chỉ vì đó là cách "thuần khiết" để làm điều đó. Bạn nên tận dụng mã đã tạo tệp để tạo/sao chép nó vào vị trí tạm thời, sử dụng nó, sau đó xóa nó. – tsells

+0

Có thể. Đó là lý do tại sao tôi đã cố gắng viết "xem xét ..." - nếu nó hoạt động cho trường hợp của bạn hơn là làm điều đó, nếu không - làm điều gì đó khác (đã được đề xuất như một câu trả lời trước đó). –

1

Một lựa chọn là đặt nó ở phía trên cùng của vật cố thử nghiệm. Sau đó, các bài kiểm tra sẽ chỉ hợp lệ khi tệp tồn tại.

[SetUp] 
public void Setup() 
{ 
    Assume.That(File.Exists(SettingsReader.XML_SETTINGS_PATH)); 
}