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

使用FakeItEasy在XUnit中伪造异步方法时返回类型不匹配问题

解决ASP.NET中XUnit+FakeItEasy异步方法测试的返回类型不匹配异常

问题场景

在ASP.NET项目中使用XUnit结合FakeItEasy测试异步控制器方法时,遇到返回类型不匹配的异常,异常信息如下:

Xunit.Sdk.XunitException: 'Expected type to be System.Threading.Tasks.Task1[[Microsoft.AspNetCore.Mvc.ActionResult1[[System.Collections.Generic.List`1[[Amazon.Models.Merchant, AmazonAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Microsoft.AspNetCore.Mvc.Core, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]], but found System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[Microsoft.AspNetCore.Mvc.ActionResult`1[[System.Collections.Generic.List`1[[Amazon.Models.Merchant, AmazonAPI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Microsoft.AspNetCore.Mvc.Core, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Runtime.CompilerServices.IAsyncStateMachine, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].'

相关代码如下:

控制器方法

[HttpGet]
public async Task<ActionResult<List<Merchant>>> GetMerchants()
{
    return await _repository.GetMerchant();
}

仓储实现

public async Task<List<Merchant>> GetMerchant()
{
    try
    {
        return await _context.Merchants.ToListAsync();
    }
    catch
    {
        throw new NotImplementedException();
    }
}

修正后的测试代码

using Amazon.Controllers;
using Amazon.Models;
using Amazon.Repository;
using FakeItEasy;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;

namespace AmazonAPITest.Amazon_Controller_Merchant
{
    public class Merchant_Controller_Test
    {
        private readonly IMerchantRepository _merchantRepository;

        public Merchant_Controller_Test()
        {
            _merchantRepository = A.Fake<IMerchantRepository>();
        }

        [Fact]
        public async Task MerchantController_GetMerchants_ReturnsActionResultWithMerchantList()
        {
            // Arrange
            var fakeMerchantList = A.Fake<List<Merchant>>();
            A.CallTo(() => _merchantRepository.GetMerchant()).Returns(Task.FromResult(fakeMerchantList));
            
            var merchantController = new MerchantController(_merchantRepository);

            // Act
            var result = await merchantController.GetMerchants();

            // Assert
            result.Should().NotBeNull();
            result.Should().BeAssignableTo<ActionResult<List<Merchant>>>();
        }
    }
}

核心问题与解决要点

  1. 测试方法必须异步化
    原测试方法为void类型,调用异步控制器方法时无法等待执行完成,且编译器会生成特殊的Task子类。需将测试方法改为async Task类型,并用await等待控制器方法执行完毕。

  2. 禁止Fake Task类型
    A.Fake<Task<T>>是错误用法,Task是编译器处理的特殊类型,不应被Fake。应使用Task.FromResult()创建已完成的Task实例,返回给Fake仓储。

  3. 断言使用类型兼容性判断
    BeOfType要求严格匹配类型,但异步方法返回的Task是编译器生成的AsyncStateMachineBox子类(继承自目标Task类型),因此改用BeAssignableTo来判断类型兼容性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 00:45:54