2015-01-26 254 views
2

我是單元測試async方法返回List<T>。該方法依賴於映射類/接口。在我的單元測試中,我使用moq來嘲笑映射類。測試運行正常,並且返回的列表包含項目,但項目的值爲空。我認爲這個問題是因爲我沒有正確地剔除映射類方法。我沒有很多測試經驗,所以任何指導都是值得讚賞的。單元測試使用Moq

測試方法:

[TestMethod] 
[TestCategory("CSR.Data.Tests.Services.ServiceSearchTest")] 
public void SearchAccount() 
    { 
     // Arrange     
     var mapper = new Mock<CSR.Data.Mapping.Interfaces.IMapper<Account, AccountDTO>>(); 

     mapper.Setup(i => i.Initialize()); 
     mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns(It.IsAny<Account>); 
     mapper.Setup(i => i.DomainToDto(It.IsAny<Account>())).Returns(It.IsAny<AccountDTO>); 

     var service = new ServiceSearch(null,mapper.Object);   
     string accountNumber = "123"; 
     string accountName = ""; 

     // Act 
     var results = service.SearchAccount(accountNumber, accountName);    

     // Assert 
     Assert.IsTrue(results.Result.Count >= 1); 
     } 

方法/類,我測試:

public class ServiceSearch : IServiceSearch 
    { 
    public ServiceSearch(IMapper<Claim, ClaimDTO> claimMapper, IMapper<Account, AccountDTO> accountMapper) 
      { 
       _claimMapper = claimMapper; 
       _accountMapper = accountMapper; 
      } 

    public async Task<List<AccountDTO>> SearchAccount(string accountNumber, string accountName) 
      { 
       var accounts = new List<Account>(); 
       var accountDTOs = new List<AccountDTO>(); 
       var results = await Task.Run(() => base.AccountSearch(accountNumber, accountName).Result); 

       if (results != null && results.Count > 0) 
       { 
        //Map DH to Domain 
        _accountMapper.Initialize(); 

        foreach (AccountSearchResult result in results) 
        { 
         accounts.Add(_accountMapper.ToDomain(result)); 
        } 

        //Map Domain to DTO 
        foreach (Account account in accounts) 
        { 
         accountDTOs.Add(_accountMapper.DomainToDto(account)); 
        } 
       } 
       return accountDTOs; 
      } 
} 
+0

您應該避免在'async'代碼中使用'Result'(也可能是'Task.Run')。 – 2015-01-26 18:49:50

+0

@StephenCleary ...我不想要任務的價值嗎? Task.Run在這裏有什麼問題?如果您認爲這是值得的,我會創建另一個問題。 – 2015-01-26 19:10:12

+0

'await'是檢索結果的正確機制。 'Task.Run'應該只用於從UI層調用CPU綁定的方法,這在這段代碼中並不是這種情況。 – 2015-01-26 19:47:02

回答

0

你實際上並沒有建立在 「.Returns」 調用的對象。您需要確保將「.Returns」設置爲實際具有值的對象。

+0

請參閱我對史蒂夫米切姆的迴應。 – 2015-01-26 18:59:03

1

這不是使用Mock對象的最佳位置,因爲您將花費大量時間編寫測試對象和模擬結果。設置調用的問題在於您尚未配置任何要返回結果的內容。一個正確的例子是:

// you would fully configure this object 
AccountDTO expectedResult = new AccountDTO(); 

mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns(expectedResult); 

現在您可以使用設置爲不同輸入配置不同的accountDTO。

也叫配置回調產生在測試時的帳戶:

mapper.Setup(i => i.ToDomain(It.IsAny<AccountSearchResult>())).Returns<AccountSearchResult>(sr => { 
    // build and return your dto here 
}); 

但是,除非你的映射器是昂貴的運行或創造,我想你最好還是先確保它是完全測試和可接受的,然後用它來直接生成DTO,而不是試圖嘲笑它。

+0

我刪除了模擬並使用了IMapper的一個實例,它工作正常。我可以做到這一點,但我不明白爲什麼模擬不起作用。不是嘲笑這樣做的正確方法,以避免緊耦合等?我也按照您的建議更改了回報,並返回具有空屬性值的類。我需要手動填充這些類來讓它們工作嗎? – 2015-01-26 18:58:26

+0

模擬和何時使用現有實現之間的界限對我來說是模糊的。當我嘲笑一個系統時,我花了很多時間試圖保持最新的測試。有了像數據映射這樣的東西,你仍然有一個'鬆耦合',因爲你不依賴於映射器類的實現,但是你依賴於輸入和輸出的結構。如果你所做的只是在不同類型的實例之間複製屬性,那麼這就是你所有的模擬所要做的。 – 2015-01-26 20:09:03

+1

@BigDaddy是的,你需要手動填充類。 (或使用現有的實現。)如果你想真正的隔離,你需要手動填充。 – 2015-01-29 21:46:28