2011-10-14 38 views
7

這是我的c#單元測試設計問題:C#單元測試設計問題:如何減少單元測試寫入冗餘?

我有一個測試,我想運行一些修改文件的代碼。我的測試將運行修改文件的代碼,然後檢查結果。目前相當直截了當......

問題是,我有大約10個文件(很快會更多),我想運行相同的單元測試。我不想爲每個文件寫一個新的單元測試,當測試本身真的是一樣的時候。

我可以編寫一個測試來查詢文件夾中的文件,然後在每個文件上運行測試邏輯,但是使用此方法只會報告整個文件集的一個通過/失敗結果。

編號喜歡創建某種動態系統,其中我放置在特定文件夾中的每個文件都通過相同的單元測試運行。因此,如果文件夾中有25個文件,則測試運行25次,單元測試reults報告運行25個測試,並且包含每個測試的單獨通過/失敗。

任何想法如何或如果這可以在C#單元測試中完成?或者與一個nunit測試?

謝謝!我希望這不是一個重複的問題。我環顧四周,但找不到任何東西。

+1

有些人會爭辯說,涉及IO(在這種情況下操縱文件系統)的測試不是單元測試。另一種方法是將IO操作表示爲可注入的依賴關係。然而,大多數的System.IO類型(當然還有靜態)並不適用於此。我使用的一種方法是創建簡單方法轉發類型和相應接口的代理程序集。這允許您保留這個瘦代理層未經測試,並且您的邏輯層完全經過_unit_測試。微軟莫爾斯有效地做到了這一點,但這仍然是一個在製品。 –

回答

3

另一種選擇是使用T4模板動態生成基於文件的目錄中的編號爲你測試。將這個「.tt」文件添加到你的單元測試項目中。

現在,無論何時只要在Visual Studio中按下「在解決方案中運行所有測試」按鈕之前進行構建,就應該在單元測試中爲文件名中的所有文件生成單元測試。然後,您的測試運行應該包含所有測試文件及其狀態的好列表。

<#@ template debug="false" hostspecific="true" language="C#v3.5" #> 
<#@ assembly name="System.Core.dll" #> 
<#@ assembly name="System.Data.dll" #> 
<#@ import namespace="System.IO" #> 
<#@ import namespace="System.Collections.Generic" #> 
<#@ import namespace="System.Linq" #> 
<#@ output extension=".cs" #> 
<# 
      string inputDirectory = @"d:\temp"; 
      var files = System.IO.Directory.GetFiles(inputDirectory); 
#> 
using System; 
using System.Text; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace TestProject1 
{ 
    [TestClass] 
    public class UnitTest1 
    { 
     <# foreach (string filePath in files) { #> 
     [TestMethod] 
     public void TestingFile_<#=System.IO.Path.GetFileNameWithoutExtension(filePath).Replace(' ','_').Replace('-','_')#>() 
     { 
     File currentFile = System.IO.File.Open(@"<#= filePath #>", FileMode.Open); 
     // TODO: Put your standard test code here which will use the file you opened above 
     } 
     <# } #> 
    } 
} 
+1

這是很棒的東西!直到現在我還不知道這個功能,所以我真的很高興我終於問了一個關於stackoverflow的問題! :) – fj40bryan

+1

謝謝大家爲我的問題提供很好的輸入! – fj40bryan

10

這聽起來像你需要的是一個參數化測試用例:見http://www.nunit.org/index.php?p=testCaseSource&r=2.5

所以:

[TestFixture] 
public class Tests 
{ 
    static string[] FileNames = new string[] 
        { "mary.txt", "mungo.txt", "midge.txt" }; 

    [Test, TestCaseSource("FileNames")] 
    public void TestMethod(string fileName) 
    { 
     Assert.That(File.Exists(fileName)); 
    } 
} 

[TestCaseSource]屬性告訴NUnit的從字符串數組獲取字符串參數的值。

但是,該方法需要靜態文件名的常量。如果你寧願有一個編程方法,從數據庫中讀取文件或類似嘗試一個工廠類,像這樣:

[TestFixture] 
public class Tests 
{ 
    [Test, TestCaseSource(typeof(FilenameFactory), "FileNames")] 
    public bool FileCheck(string fileName) 
    { 
     return File.Exists(fileName); 
    } 
} 

public class FilenameFactory 
{ 
    public static IEnumerable FileNames 
    { 
     get 
     { 
      foreach (var filename in 
        Directory.EnumerateFiles(Environment.CurrentDirectory)) 
      { 
       yield return new TestCaseData(filename).Returns(true); 
      } 
     } 
    } 
} 

TestCaseData類產生「測試案例」,它具有可以通過流暢的設定預期接口。

+0

這也是一個非常棒的解決方案。謝謝你,傑里米。 – fj40bryan

0

首先,測試依賴外部來源,如磁盤上的文件不是嚴格的單元測試(意見)。

您正在尋找的是一種數據驅動的測試方法,然後您應該尋找支持它的工具,如MSTestMBunit。 (按照鏈接瞭解更多信息)。

然後,你可以做這樣的事情(用MbUnit的):

[TestFixture] 
public class MyTestFixture 
{ 
    [Test] 
    public void WordCounter([TextData(ResourcePath = "Data.txt")] string text) 
    { 
     var wordCounter = new WordCounter(text); 
     int count = wordCounter.Count("Firecrest"); 
     Assert.AreEqual(4, count); // Should not include the plural form "Firecrests". 
    } 
}