2017-07-27 52 views
1

我有一個服務調用包裝函數,它除了在調用中將參數轉發給服務外,什麼也不做。包裝的原因是我們可以使用一個DI容器來包裝注入,因此被模擬進行單元測試。如何在單元測試簡單方法時引發異常

這裏是包裝的樣子

public class WeatherChannelWrapper : IWeatherServiceWrapper 
{ 
    public GetLocalWeather(string zipcode) 
    { 
     TWCProxy.GetCurrentCondition(zipcode, DateTime.Now.ToString("MM/dd/yyyy hh:mm")); 
    } 
} 

一切正常,現在我有一個要求,吞下對TWCProxy的崩潰例外。所以現在我的包裝看起來像這樣。

public class WeatherChannelWrapper : IWeatherServiceWrapper 
{ 
    private readonly IExceptionLogger exceptionLogger; 

    public WeatherChannelWrapper(IExceptionLogger logger) 
    { 
     this.exceptionLogger = logger; 
    } 
    public GetLocalWeather(string zipcode) 
    { 
     try 
     { 
      TWCProxy.GetCurrentCondition(zipcode, DateTime.Now.ToString("MM/dd/yyyy hh:mm")); 
     } 
     catch (Exception e) 
     { 
      exceptionLogger.Log(e); 
     } 
    } 
} 

我必須寫下面的單元測試

  1. GetLocalWeather()時,內部發生異常
  2. GetLocalWeather(不崩潰的應用程序)記錄異常

我們測試兩種情況,我需要以某種方式誘發崩潰;我該如何使用NUnit和Automoq/Moq?

+0

好像你要測試通過傳遞一個無效的郵政編碼或任何會導致'TWCProxy.GetCurrentCondition'拋出一個n例外。 – juharr

+1

https://www.bing.com/search?q=c%23%20moq%20throw ...或者你需要澄清你在找什麼。 –

+0

@juharr是的,但這不會是拋出異常的可靠方法。這樣你就可以預測/依賴第三方API的行爲。 – fahadash

回答

1

如果不重構代碼,您需要做的是在TWCProxy類上使用墊片。 Moq不提供墊片,因此您可能需要使用第三方庫。

我不確定您是否有權使用Microsoft Fakes之類的東西,但如果您這樣做,可以在單元測試中輕鬆實現。

https://msdn.microsoft.com/en-us/library/hh549175.aspx

首先,引用您的第三方庫,並創建一個假的lib。在VS(我使用企業,不知道哪些版本具有該功能),這可以在您的測試項目中完成,通過引用庫,然後在參考中,右鍵單擊庫和Add Fake Assembly。然後建立你的項目。

然後,在你的單元測試,你可以設置墊片如下

[TestMethod] 
public void MyTestMethod() 
{ 
    using (ShimsContext.Create()) 
    { 
     // fake assembly will have a long method name for the signature of the call. omitted for simplicity 
     ShimTWCProxy.GetCurrentCondition[...] =() => {throw new Exception("message")}; 

     // instantiate and execute test code 
     var logger = new Mock<IExceptionLogger>(); 
     var testedClass = new WeatherChannelWrapper (logger.Object); 
     testedClass.GetLocalWeather("..."); 
     svc.Verify(x => x.Log(It.IsAny<string>()), Times.Once); 

    } 
} 

另一種方法是將傳遞到類的方法的委託,這可能會默認爲您的靜態類,然後讓你可以在運行時重寫它,儘管這可能有點麻煩。讓我知道你是否想要一個例子。

請注意,MS Fakes並不能很好地與一些測試跑步者/框架搭配使用。例如,它似乎與NUnit和MSTest適配器以及MSTest和Resharper測試運行器一起使用,但不支持NUnit和Resharper運行器。

也可能有其他的填充/僞造解決方案,但我沒有立即意識到它們。

1

更改WeatherChannelWrapper,以便您可以覆蓋它以拋出異常。例如,通過加入像CallTwcProxy受保護的虛擬方法如下:

public class WeatherChannelWrapper : IWeatherServiceWrapper 
{ 
    private readonly IExceptionLogger exceptionLogger; 

    public WeatherChannelWrapper(IExceptionLogger logger) 
    { 
     this.exceptionLogger = logger; 
    } 

    public GetLocalWeather(string zipcode) 
    { 
     try 
     { 
      CallTwcProxy(zipcode); 
     } 
     catch (Exception e) 
     { 
      exceptionLogger.Log(e); 
     } 
    } 

    protected virtual void CallTwcProxy(string zipcode) 
    { 
     TWCProxy.GetCurrentCondition(zipcode, DateTime.Now.ToString("MM/dd/yyyy hh:mm")); 
    } 
} 

然後你就可以僞造它通過在您的測試項目覆蓋CallTwcProxy方法拋出一個異常:

public class FakeWeatherChannelWrapper : WeatherChannelWrapper 
{ 
    protected override virtual void CallTwcProxy(string zipcode) 
    { 
     throw new Exception("force exception to throw"); 
    } 
} 

現在你有一個假的WeatherChannelWrapper其拋出您可以在您的測試中使用的異常:

public class WeatherChannelWrapperTests 
{ 
    [Test] 
    public void GetLocalWeather_WhenInternalExceptionOccurs_LogsException_Test() 
    { 
     var loggerMock = new Mock<IExceptionLogger>(); 
     var sut = new FakeWeatherChannelWrapper(loggerMock.Object); 

     sut.GetLocalWeather("12345"); 

     // Assert Exception is logged 
     loggerMock.Verify(logger => logger.Log(It.IsAny<Exception>()), Times.Once); 

     // And practically this also tests that it doesn't crash even if exception is thrown 
    } 
} 
相關問題