单元测试使用Moq
我是单元测试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;
}
}
你实际上并没有建立在 “.Returns” 调用的对象。您需要确保将“.Returns”设置为实际具有值的对象。
请参阅我对史蒂夫米切姆的回应。 – 2015-01-26 18:59:03
这不是使用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的一个实例,它工作正常。我可以做到这一点,但我不明白为什么模拟不起作用。不是嘲笑这样做的正确方法,以避免紧耦合等?我也按照您的建议更改了回报,并返回具有空属性值的类。我需要手动填充这些类来让它们工作吗? – 2015-01-26 18:58:26
模拟和何时使用现有实现之间的界限对我来说是模糊的。当我嘲笑一个系统时,我花了很多时间试图保持最新的测试。有了像数据映射这样的东西,你仍然有一个'松耦合',因为你不依赖于映射器类的实现,但是你依赖于输入和输出的结构。如果你所做的只是在不同类型的实例之间复制属性,那么这就是你所有的模拟所要做的。 – 2015-01-26 20:09:03
@BigDaddy是的,你需要手动填充类。 (或使用现有的实现。)如果你想真正的隔离,你需要手动填充。 – 2015-01-29 21:46:28
您应该避免在'async'代码中使用'Result'(也可能是'Task.Run')。 – 2015-01-26 18:49:50
@StephenCleary ...我不想要任务的价值吗? Task.Run在这里有什么问题?如果您认为这是值得的,我会创建另一个问题。 – 2015-01-26 19:10:12
'await'是检索结果的正确机制。 'Task.Run'应该只用于从UI层调用CPU绑定的方法,这在这段代码中并不是这种情况。 – 2015-01-26 19:47:02