2009-02-28 36 views
1

我想更好地使用NUnit來測試我編寫的應用程序,但我經常發現,我編寫的單元測試可以直接鏈接到環境或底層數據庫開發機器。NUnit測試應用程序,而不是環境或數據庫

讓我舉個例子。

我正在寫一個類,它有一個單一的責任來回顧一個字符串,該字符串已被另一個應用程序存儲在註冊表中。密鑰存儲在HKCU \ Software \ CustomApplication \ IniPath中。

測試我最終寫作看起來像這樣;

[Test] 
public void GetIniDir() 
{ 
    RegistryReader r = new RegistryReader(); 
    Assert.AreEqual(@"C:\Programfiles\CustomApplication\SomeDir", r.IniDir); 
} 

但這裏的問題是,字符串@ 「C:\ PROGRAMFILES \ CustomApplication \ SomeDir」 實際上只是正確的現在。明天它可能會變成@「C:\ Anotherdir \ SomeDir」,並突然間斷了我的單元測試,即使代碼沒有改變。

當我創建一個對數據庫執行CRUD操作的類時,也會出現此問題。數據庫中的數據可能會一直改變,這又會導致測試失敗。所以即使我的班級做了它打算做的事情,它也會失敗,因爲數據庫會返回我最初編寫測試時所擁有的更多客戶。

[Test] 
public void GetAllCustomersCount() 
{ 
    DAL d = new DAL(); 
    Assert.AreEqual(249, d.GetCustomerCount()); 
} 

你們有沒有寫測試的提示,它不依賴於周圍的環境呢?

回答

6

這個問題的解決方案是衆所周知的:mocking。將代碼重構爲接口,然後開發假類以實現這些接口或使用嘲笑框架來嘲笑它們,例如RhinoMocks,easyMock,Moq等。人。使用假或模擬類允許您定義接口爲您的測試返回的內容,而無需實際與外部實體(如數據庫)交互。

有關通過SO模擬的更多信息,請嘗試以下Google搜索:http://www.google.com/search?q=mock+site:stackoverflow.com。您可能還會對以下定義感興趣:What's the difference between faking, mocking, and stubbing?

此外,良好的開發實踐(如依賴注入(如@Patrik建議),允許將類與其依賴關係解耦,以及避免靜態對象,這讓單元測試變得更加困難,這將有助於您的測試。使用TDD實踐 - 首先開發測試 - 將幫助您自然地開發融合了這些設計原則的應用程序。

0

其他方法是爲測試創建單獨的數據庫。

+1

但是,你不是真的單元測試,你是集成測試。 – 2009-02-28 16:10:59

2

最簡單的方法是使用依賴注入來顯式依賴。例如,你的第一個例子依賴於註冊表,通過傳遞一個IRegistry(你將定義的一個接口)實例來顯式地明確這個依賴關係,然後只使用這個傳入的依賴關係從註冊表中讀取。通過這種方式,您可以在測試中傳入IRegistry存根時始終返回已知值,而在生產中您使用的是實際從註冊表中讀取的實現。

public interface IRegistry 
{ 
    string GetCurrentUserValue(string key); 
} 

public class RegistryReader 
{ 
    public RegistryReader(IRegistry registry) 
    { 
     ... 
     // make the dependency explicit in the constructor. 
    } 
} 
[TestFixture] 
public class RegistryReaderTests 
{ 
    [Test] 
    public void Foo_test() 
    { 
     var stub = new StubRegistry(); 
     stub.ReturnValue = "known value"; 

     RegistryReader testedReader = new RegistryReader(stub); 

     // test here... 
    } 

    public class StubRegistry 
     : IRegistry 
    { 
     public string ReturnValue; 

     public string GetCurrentUserValue(string key) 
     { 
      return ReturnValue; 
     } 
    } 
} 

在這個快速示例中,我使用手動存根,當然,您可以使用任何模擬框架。

0

您應該瞭解控制原理的反轉以及如何使用依賴注入技術 - 這真的可以幫助您編寫可測試的代碼。

就你而言,你應該有一個界面 - 例如IIniDirProvider - 這是由RegistryBasedIniDirProvider實現的,它可以提供基於註冊表中特定鍵的初始目錄。

然後,當其他一些類需要查找的初始目錄,其他類應具有以下構造函數:

public SomeOtherClass(IIniDirProvider iniDirProvider) 
{ 
    this.iniDirProvider = iniDirProvider; 
} 

- 允許你在一個模擬IIniDirProvider傳遞,當你需要進行單元測試SomeOtherClass 。這樣你的單元測試就不會依賴註冊表中的任何東西。

相關問題