2017-10-17 70 views
1

考慮用try catch這樣的方法:如何單元測試,如果調用靜態記錄發生

try 
{ 
    person = this.personRepo.GetPerson(name); 
} 
catch (PersonException) 
{ 
    LogHelper.LogDebug("PersonService", "No Person found!"); 
} 

在單元測試中,personRepo是僞造與FakeItEasy:

A.CallTo(() => this.personRepository.GetPerson(personName)).Throws(new PersonException("Person not found")); 

問題:

如何檢查靜態記錄器是否被調用?

+0

因爲'LogHelper.LogDebug'是靜態方法 - 你不能嘲笑它。所以你需要測試'LogDebug'的實際行爲。如果它寫入文件 - 讀取文件,如果寫入數據庫 - 讀取數據庫。如果'LogHelper'可配置 - 您可以將其配置爲可以輕鬆測試的輸出(例如MemoryStream)。但是潔具,它是靜態方法,如果你並行運行測試 - 其他測試會受到相同配置的影響。適當的可測試解決方案 - 引入「記錄器」的抽象並將其注入課堂。實際的實現仍然可以調用靜態方法。 – Fabio

+0

這通常很複雜。這也是避免靜力學的一個原因。您可以使用MS Fakes(Shim Types),但AFAIK您需要Visual Studio Enterprise(或以前的最終版本)。否則,您可能會應用重構。如果依賴注入不是您的選擇,那麼您可以首先引入一個單例LogHelper.Instance.LogDebug(...),它可以在單元測試中設置。 – Peit

+0

如果發生異常,您可以嘗試測試。但在測試結束時,您應該刪除已保存的數據。不知道這是否是最好的方法。 – Sasha

回答

4

這裏的假設是personRepo被注入到被測主題中。因此我也假設你正在使用DI。

當前顯示的代碼與靜態實現問題緊密耦合,這使得難以單獨測試主題。

爲了使主題更加靈活,更易於維護和隔離測試,主題需要重構以取決於抽象而不是結核。

在抽象背後封裝靜態LogHelper

public interface ILogger { 
    void LogDebug(string category, string msg); 
    //...other members 
} 

這將包裝所需的行爲/功能

public class LogHelperWrapper : ILogger { 
    public void LogDebug(string source, string msg) { 
     LogHelper.LogDebug(source, msg); 
    } 

    //...other members 
} 

主題會利用抽象,這將重構通過構造注射遵循顯式依賴的原則。

private ILogger log; //set via constructor injection 
try { 
    person = this.personRepo.GetPerson(name); 
} catch (PersonException) { 
    this.log.LogDebug("PersonService", "No Person found!"); 
} 

這將允許被測試者在隔離測試時接收替換物。

//Arrange 
var logger = A.Fake<ILogger>(); 
//...other arrangements 

//Act 
//...exercise test 

//Assertion 
A.CallTo(() => logger.LogDebug("PersonService", "No Person found!")) 
.MustHaveHappened(Repeated.Exactly.Once); 
//...other assertions.