【问题标题】:Unit Test Using Moq使用最小起订量的单元测试
【发布时间】:2015-01-26 18:06:54
【问题描述】:

我正在对返回 List<T>async 方法进行单元测试。此方法依赖于映射类/接口。在我的单元测试中,我使用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;
            }
}

【问题讨论】:

  • 您应该避免在您的async 代码中使用Result(可能还有Task.Run)。
  • @StephenCleary...我不想要任务的价值吗? Task.Run 这里有什么问题?如果您认为值得,我会再提出一个问题。
  • await 是检索结果的正确机制。 Task.Run 只能用于从 UI 层调用 CPU 绑定的方法,而在此代码中似乎并非如此。

标签: c# unit-testing moq


【解决方案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,而不是尝试模拟它.

【讨论】:

  • 我删除了模拟并使用了 IMapper 的实例,它工作正常。我可以做到这一点,但我不明白为什么模拟不起作用。模拟不是避免紧密耦合等的正确方法吗?我还按照您的建议更改了返回值,并取回了具有空属性值的类。我需要手动填充这些类以使它们工作吗?
  • 何时模拟和何时使用现有实现之间的界限对我来说是一个模糊的界限。当我过度模拟一个系统时,我花了很多时间试图让测试保持最新。对于数据映射之类的东西,您仍然具有“松散耦合”,因为您不依赖于映射器类的实现,而是依赖于输入和输出的结构。如果你所做的只是在不同类型的实例之间复制属性,那么这就是你的 mock 所做的一切。
  • @BigDaddy 是的,您需要手动填充类。 (或者使用现有的实现。)如果你想要真正的隔离,你肯定需要手动填充。
  • @MattClark 是正确的,如果您要使用 Moq,则需要手动填充预期值。
【解决方案2】:

您实际上并没有在“.Returns”调用中设置对象。您需要确保将“.Returns”设置为实际拥有一个具有值的对象。

【讨论】:

  • 请看我对 Steve Mitcham 的回复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-29
  • 1970-01-01
相关资源
最近更新 更多