You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NSubstitute模拟异步方法返回参数时遇System.InvalidCastException问题

问题:C#测试中抛出InvalidCastException异常

我有一段可正常编译的C#代码,但运行测试时抛出System.InvalidCastException异常,错误信息如下:

Unable to cast object of type 'DomainObject' to type 'System.Threading.Tasks.Task`1[DomainObject]'

测试及相关代码如下:

public class Test
{
    [Fact]
    public async Task ThisShouldWork()
    {
        // arrange
        var dto = new Dto
        {
            FName = "John",
            LName = "Doe"
        };
        
        var mock = Substitute.For<IRepository>();
        mock
            .SaveAsync(Arg.Any<DomainObject>())
            .Returns(args => args[0]);
        var service = new BusinessService(mock);
        
        // act
        var result = await service.DoSomethingAsync(dto);
        
        // assert
        await mock
            .Received(1)
            .SaveAsync(result);
    }
}

public class BusinessService
{
    private readonly IRepository _repository;

    public BusinessService(IRepository repository)
    {
        _repository = repository;
    }

    public async Task<DomainObject> DoSomethingAsync(Dto dto)
    {
        var domain = new DomainObject
        {
            FirstName = dto.FName,
            LastName = dto.LName
        };

        return await _repository.SaveAsync(domain);
    }
}

public class DomainObject
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public interface IRepository
{
    Task<DomainObject> SaveAsync(DomainObject domain);
}

public class Dto
{
    public string FName { get; set; }
    public string LName { get; set; }
}

问题原因及修复方案

原因

IRepository.SaveAsync方法的返回类型是Task<DomainObject>,但配置NSubstitute模拟对象时,直接返回了DomainObject实例,NSubstitute尝试将该实例强制转换为Task<DomainObject>类型,从而触发类型转换异常。

修复方式

有两种简洁的修复方法:

  1. 使用Task.FromResult手动包装Task
    将模拟配置代码修改为:
mock
    .SaveAsync(Arg.Any<DomainObject>())
    .Returns(args => Task.FromResult((DomainObject)args[0]));
  1. 使用NSubstitute的ReturnsAsync方法(推荐)
    ReturnsAsync是NSubstitute专门为异步方法提供的快捷方法,会自动将返回值包装为已完成的Task:
mock
    .SaveAsync(Arg.Any<DomainObject>())
    .ReturnsAsync(args => (DomainObject)args[0]);

修改后,模拟对象会正确返回Task<DomainObject>类型的结果,测试即可正常运行。

内容的提问来源于stack exchange,提问作者baynezy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:12:21