2015-01-26 208 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