gpt4 book ai didi

c# - Moq 检查是否使用另一个调用的参数调用方法

转载 作者:行者123 更新时间:2023-12-05 05:47:01 24 4
gpt4 key购买 nike

我有以下功能,我正在尝试进行单元测试

public MessageListDto GetMessageList(SimpleSearchCriteria criteria)
{
var messages = _repository.GetMessages(criteria, out int total);
return new MessageListDto(messages, total);
}

以下是我目前的测试,我能够确定 _repository.GetMessages 是使用正确的参数调用的。

但是,我如何测试第二行是否正确测试,我需要测试

  • MessageListDto 类型的新对象是用上面一行返回的两个参数构造的
  • 返回新构造的对象
[Test]
public void Test1()
{
int total = 10;
var searchCriteria = new SimpleSearchCriteria();
var mockRepo = new Mock<IMessageRepository>();
var messageService = new MessageService(mockRepo.Object);
messageService.GetMessageList(searchCriteria);
mockRepo.Verify(r => r.GetMessages(searchCriteria, out total), Times.Once);
mockRepo.Verity ??????????
}

最佳答案

正如我们在评论部分讨论的那样,您的目标是测试返回的消息是否未经任何修改就传递给了 dto 的构造函数。

使用您当前的代码,您不能这样做,因为您是在您的方法中显式创建 DTO。因此,您不能将其替换为 spy

只是为了澄清一些术语:

  • Dummy:返回虚假数据的简单代码
  • Fake:可以走捷径的有效替代品
  • stub :带有预定义数据的自定义逻辑
  • Mock:具有期望的自定义逻辑(交互式 stub )
  • Shim:自定义逻辑在运行时
  • spy :拦截器记录通话

为了能够捕获 MessageListDto 构造函数调用的参数,您需要在 GetMessageList 方法和构造函数之间引入另一个层。 (换句话说,间接)


为了简单起见,我假设 IMessageRepositoryGetMessages 返回一个 string 数组。

所以,你可以这样引入一个接口(interface):

public interface IDtoProvider
{
public MessageListDto CreateMessageList(string[] messages, int total)
=> new MessageListDto(messages, total);
}

现在让我们修改您的 MessageService 以通过其构造函数接收 IDtoProvider 实例

class MessageService
{
private readonly IMessageRepository _repository;
private readonly IDtoProvider _dtoProvider;
public MessageService(IMessageRepository repository, IDtoProvider dtoProvider)
=> (_repository, _dtoProvider) = (repository, dtoProvider);

public MessageListDto GetMessageList(SimpleSearchCriteria criteria)
{
var messages = _repository.GetMessages(criteria, out int total);
return _dtoProvider.CreateMessageList(messages, total);
}
...
}

有了这些,我们就可以编写这样的单元测试了:

//Arrange - Repo
string[] messages = new[] { "OnlyElement" };
int total = 10;
var mockRepo = new Mock<IMessageRepository>();
mockRepo
.Setup(repo => repo.GetMessages(It.IsAny<SimpleSearchCriteria>(), out total))
.Returns(messages);

//Arrange - Provider
var dto = new MessageListDto(messages, total);
string[] messagesArgument = null;
int totalArgument = -1;
var mockProvider = new Mock<IDtoProvider>();
mockProvider
.Setup(provider => provider.CreateMessageList(It.IsAny<string[]>(), It.IsAny<int>()))
.Callback<string[], int>((messages, total) => (messagesArgument, totalArgument) = (messages, total))
.Returns(dto);


//Arrange - SUT
var searchCriteria = new SimpleSearchCriteria();
var sut = new MessageService(mockRepo.Object, mockProvider.Object);

//Act
sut.GetMessageList(searchCriteria);

//Assert - Repo
mockRepo.Verify(r => r.GetMessages(searchCriteria, out total), Times.Once);

//Assert - Provider
Assert.Equal(messages, messagesArgument);
Assert.Equal(total, totalArgument);
  1. 我已经定义了 IMessageRepository 模拟的行为方式
  2. 我已经定义了 IDtoProvider 模拟的行为方式
    2.1 我在这里使用了 Callback 方法来捕获调用参数
    2.2 如果您对模拟方法执行多次调用,请考虑使用 Capture.In
  3. 我已经用模拟对象
  4. 我在 Act phase 中调用了 GetMessageList
  5. 我已针对 repo 模拟调用做出断言
  6. 我已针对 CreateMessageList
    的调用参数做出断言6.1 这里我使用了xunit的断言

关于c# - Moq 检查是否使用另一个调用的参数调用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71096523/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com