xUnit - 异步列表的模拟方法 returns null

xUnit - mocked method for the async List returns null

这是一件奇怪的事情 - 当我 运行 单元测试并将断点放在行 return Unit.Value; 上时,我看到 someResult 值为空 - 但是当我再次手动将调试器的黄色箭头移动到上一行 var someResult = await _myRepository.DoSomething(cancellationToken); 然后 someResult 变量不为空并且包含我的对象 - 为什么会发生这种情况?

单元测试片段:

//Arrange
var myList = new List<MyTable> { new MyTable() };
var myRepository = Substitute.For<IMyRepository>();
myRepository.DoSomething(Arg.Any<CancellationToken>()).Returns(myList);

var command = Substitute.For<MyCommand>();

//Act
var sut = new MyCommandHandler(myRepository);
await sut.Handle(command, Arg.Any<CancellationToken>());

我也试过:

myRepository.DoSomething(Arg.Any<CancellationToken>()).Returns(Task.FromResult(myList));

已测试class:

public class MyCommandHandler : ICommandHandler<MyCommand, Unit>
{
    private readonly IMyRepository _myRepository;

    public MyCommandHandler(IMyRepository myRepository)
    {
        _myRepository = myRepository ?? throw new ArgumentNullException(nameof(myRepository));
    }

    public async Task<Unit> Handle(MyCommand command, CancellationToken cancellationToken)
    {
        var someResult = await _myRepository.DoSomething(cancellationToken);

        ...
        return Unit.Value;
    }
}

public class MyRepository : IMyRepository
{
    private readonly MyDbContext _context;

    public MyRepository(MyDbContext context)
    {
        _context = context;
    }

    public async Task<List<MyTable>> DoSomething(CancellationToken cancellationToken = default)
    {
        return await _context.MyTable
            .AsNoTracking()
            .Where(...)
            .ToListAsync(cancellationToken);
    }
}

我认为您 Handle 调用中的 Arg.Any<CancellationToken>() 匹配器是问题所在。

改变

await sut.Handle(command, Arg.Any<CancellationToken>());

await sut.Handle(command, default);

测试成功。匹配器用于配置替代和检查接收到的调用,而不是实际调用本身。

可以找到一个工作示例 here。我没有足够的资源继续复制 Unit 及其用法,但能够观察并解决您在没有它时遇到的相同问题。