2014-06-05 53 views
0

我都迎合了這種情況,當一個配置密鑰尚未在我的業務邏輯設置如下:單元測試例外通過嘗試catch處理

public class Presenter 
{ 
private readonly IView view;  

    public Presenter(IView view) 
    { 
    this.view = view;   
    } 

    public void DoStuff() 
    { 
     try 
     { 
      String someKey = ConfigurationManager.AppSettings["SomeKey"].ToString(); 

      if (string.IsNullOrEmpty(someKey)) 
      {      
       throw new InvalidOperationException("SomeKey not set."); 
      } 

      // do stuff 
     } 
     catch (InvalidOperationException ex) 
     { 
      // provide view with friendly error 

      // log error     
     } 
    } 
} 

我在測試的嘗試,當關鍵是這個錯誤occurrs未設置:

[TestMethod] 
public void Presenter_DoStuff_Should_Throw_InvalidOperationException_When_SomeKey_Not_Supplied() 
{ 
    // Arrange 
    mockIView = new Mock<IView>();    
    presenter = new Presenter(mockIView.Object); 

    // Act 

    // Assert  
    // NUnit here as more precise  
    NUnit.Framework.Assert.Throws<InvalidOperationException>(() => presenter.DoStuff(), "SomeKey not set."); 
} 
  1. 如何讓我的測試通過,因爲它代表?它目前失敗,因爲try-catch爲了記錄目的而吞吞異常。測試通過沒有try-catch。這是AppSettings["SomeKey"]手動設置爲空字符串。

  2. 其次,如何在測試中指定someKeyDoStuff爲空以便實際測試此情況而無需手動刪除密鑰設置?

任何幫助是非常感謝,因爲我是新的單元測試。

+5

爲什麼你使用邏輯流異常?一個簡單的'if'語句來檢查配置設置是否存在也可以。例外應該用於例外行爲,而不是簡單的條件檢查。至於測試,你的方法實際上並沒有拋出異常來調用代碼,所以測試不正確。你在測試中究竟想要驗證什麼? – David

回答

0

首先,你的測試是無效的設計,因爲你的方法實際上並沒有調用代碼的例外。這是因爲你立即捕捉並處理了這個異常。這實際上是一個非常不正確的例外使用。沒有必要根據條件進行拋出,然後立即捕獲,當你在邏輯上需要做的就是檢查該條件。類似這樣的:

public void DoStuff() 
{ 
    var someKey = ConfigurationManager.AppSettings["SomeKey"]; 
    if (string.IsNullOrEmpty(someKey)) 
    { 
     // provide view with friendly error 
     // log error 
     return; 
    } 
    // do stuff 
} 

現在問題變成了......你在測試什麼?這種方法的實際業務邏輯是:

// do stuff 

所以希望這是測試的關鍵焦點。現在,爲了達到100%的代碼覆蓋率,您還需要測試該條件塊中的內容。爲了做到這一點,你需要模擬條件。但是,你有一個外部的依賴:

ConfigurationManager 

爲了測試邏輯,你將需要模擬這種依賴性。對此的一般方法是爲依賴項創建一種包裝對象。在這種特殊情況下它可能是簡單的東西如:

public class ConfigurationWrapper 
{ 
    public virtual string SomeKey 
    { 
     get 
     { 
      return ConfigurationManager.AppSettings["SomeKey"]; 
     } 
    } 
} 

這可能是從具有DoStuff,甚至嵌套類分開。取決於你想在哪裏/如何使用它。當然,它可以擴展爲包裝其他配置依賴項。然後在DoStuff的課程中,您將爲此包裝器創建一個屬性。事情是這樣的:

private ConfigurationWrapper _config; 
public ConfigurationWrapper Configuration 
{ 
    get 
    { 
     if (_config == null) 
      _config = new ConfigurationWrapper(); 
     return _config; 
    } 
    set { _config = value; } 
} 

而且用它DoStuff()

var someKey = this.Configuration.SomeKey; 

現在上ConfigurationManager的依賴被包裹在一個mockable對象。所以在你的單元測試中,你會創建一個模擬ConfigurationWrapper對象並將其設置在被測試的對象上。喜歡的東西:

var mockConfig = new Mock<ConfigurationWrapper>(); 
presenter.Configuration = mockConfig; 

您可以設置模擬返回一個有效的值或空字符串爲.SomeKey財產,這取決於任何給定的測試需求。然後你會驗證條件語句產生的任何副作用。 (我認爲「友好的錯誤信息」和「日誌記錄」,其中可能涉及進一步的模擬,目前我不知道)

當然,要達到100%的覆蓋率,您還需要添加另一種測試是在外部未設置包裝的情況下包裝的默認情況。這應該是一個相當簡單的測試:

// arrange 
// no mocks to set up 

// act 
var presenter = new Presenter(null); 

// assert 
Assert.IsNotNull(presenter.Configuration); 
+0

感謝您爲我清理一些東西。非常感激。 – user120455