使用 NSubstitute 模拟方法两次,首先抛出错误,然后为同一个调用的签名请求抛出 return 值

Mock a method twice with NSubstitute to first throw error and later return value for the same called signature request

我想用 NSubstitute 模拟一个方法两次,首先抛出错误,然后为同一个调用的签名请求抛出 return 值。

public interface IMyAction
{
    public Task<MyDto> Upsert(CreateRequest requestDto);
}

public class MyAction : IMyAction
{

    private readonly IMyRepository _repository;
    
    public MyAction(IMyRepository repository)
    {
        _repository = repository;
    }
    
    public Task<MyDto> Upsert(CreateRequest requestDto){
    {
        var domainEntity = await _repository.Get(requestDto.Param1);
        if(domainEntity == null)
        {
            try
            {
                // try to create entity
            }
            catch(RecordExistsException) // Throws when another concurrent request creates the same entity. Need to test this catch block scenario
            {
                domainEntity = await _repository.Get(requestDto.Param1);
                // 
                //...perform update operation using the domainEntity and requestDto
                //
            }
            catch(Exception ex)
            {
                throw
            }
        }
    }
}

我有一个边缘情况,我希望第一次调用应该抛出异常,第二次调用应该 return dto。两个调用的参数值相同。

我正在使用 NSubstitute 模拟 xunit 测试中的依赖关系。

我的设置:

IMyRepository _repository = Substitute.For<IMyRepository>();
var myAction = new MyAction(_repository);

_repository.Get(Arg.Any<string>()).Throws<NotFoundException>();
_repository.When(x => x.Get(Arg.Is<string>(r => r == "id1")))
           .Do(x => _repository.Get(Arg.Is<string>(r => r == "id1")).Returns(new MyDto()));

期望:

_repository.Get("id1").Throws<NotFoundException>(); // first call invocation
_repository.Get("id1").Returns(new MyDto()); // second call invocation

但是当 myAction.Upsert(new CreateRequest()); 调用 domainEntity 时在第一次调用中得到 returned 而不是抛出异常。

深入研究 SO 后,我找到了一个解决方案 here

对于我的情况,我通过如下模拟解决了这个问题-

_repository.Get("id1").Returns(x => throw new NotFoundException(), x => new MyDto());

Returns() 还支持将多个函数传递给 return from,这允许序列中的一个调用抛出异常或执行其他操作。