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

如何反序列化控制器Action的OkResult?测试遇BSON序列化异常

问题

为使用MongoDB数据访问层的API编写Mock的xUnit测试时,无法将控制器返回的OkResult解析为JSON/BSON,调试可见目标数据,但抛出BSON序列化异常:

MongoDB.Bson.BsonSerializationException : 序列化Microsoft.AspNetCore.Mvc.ObjectResult的Value属性时出错:类型System.Collections.Generic.List`1[[DataAccess.Models.CyberGood, DataAccess, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]未配置为此ObjectSerializer实例的允许类型。

相关代码如下:

CyberGood模型

namespace DataAccess.Models;
[BsonIgnoreExtraElements]
public class CyberGood
{
    [BsonId]
    [BsonElement("id")]
    public ObjectId Id { get; set; }

    [BsonElement("name")]
    public string Name { get; set; }

    [BsonElement("description")]
    public string Description { get; set; }

    [BsonElement("insideOf")]
    public string? InsideOf { get; set; }

    [BsonElement("madeIn")]
    public string MadeIn { get; set; }

    [BsonElement("price")]
    public decimal Price { get; set; }

    [BsonElement("amount")]
    public int Amount { get; set; }
}

控制器代码

[Route("api/[controller]")]
[ApiController]
public class CyberGoodController : ControllerBase
{
    private readonly ICyberGoodService _cyberGoodService;

    public CyberGoodController(ICyberGoodService cyberGoodService)
    {
        _cyberGoodService = cyberGoodService;
    }

    [HttpGet]
    public async Task<IActionResult> GetAllCyberGoodAsync()
    {
        try
        {
            var cyberGoods = await _cyberGoodService.GetAllCyberGoodAsync();
            return Ok(cyberGoods);
        }
        catch (Exception ex)
        {
            return BadRequest(ex.Message);
        }
    }
}

原出错测试用例

[Fact]
[Obsolete]
public async Task GetAll_CyberGoods_ReturnsList()
{
    //Arrange
    var mock = new Mock<ICyberGoodService>();
    mock.Setup(d => d.GetAllCyberGoodAsync()).ReturnsAsync(GetTestCyberGoods());
    var service = new CyberGoodController(mock.Object);
    var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) 
    || type.FullName.StartsWith("DataAccess") 
    || type.FullName.StartsWith("Microsoft.AspNetCore.Mvc.OkObjectResult")); 
    BsonSerializer.RegisterSerializer(objectSerializer);

    //Act
    IActionResult result = await service.GetAllCyberGoodAsync();
    var bsonRes = BsonSerializer.Deserialize<List<CyberGood>>(result.ToBson());

    //Assert
    Assert.Equal(GetTestCyberGoods().Count, bsonRes.Count);
}
解决方案

无需通过BSON序列化/反序列化提取OkResult中的数据,直接将IActionResult转换为OkObjectResult,取出其Value属性并强转为目标类型即可,这是测试ASP.NET Core控制器返回值的标准方式:

修改后的测试用例

[Fact]
public async Task GetAll_CyberGoods_ReturnsList()
{
    //Arrange
    var mock = new Mock<ICyberGoodService>();
    var testData = GetTestCyberGoods();
    mock.Setup(d => d.GetAllCyberGoodAsync()).ReturnsAsync(testData);
    var controller = new CyberGoodController(mock.Object);

    //Act
    var result = await controller.GetAllCyberGoodAsync();
    // 验证结果为OkObjectResult并转换类型
    var okResult = Assert.IsType<OkObjectResult>(result);
    // 提取返回数据并验证类型
    var returnedGoods = Assert.IsType<List<CyberGood>>(okResult.Value);

    //Assert
    Assert.Equal(testData.Count, returnedGoods.Count);
    // 可进一步验证每个元素的属性匹配
    for (int i = 0; i < testData.Count; i++)
    {
        Assert.Equal(testData[i].Id, returnedGoods[i].Id);
        Assert.Equal(testData[i].Name, returnedGoods[i].Name);
        // 其他属性按需添加验证
    }
}

原代码出错原因

原代码尝试序列化整个OkObjectResult到BSON,但ObjectSerializer未允许List<CyberGood>类型的序列化——泛型列表的FullName以System.Collections.Generic.List开头,并不符合type.FullName.StartsWith("DataAccess")的规则,因此触发异常。直接提取OkObjectResult的Value则完全绕开了不必要的BSON序列化步骤,更高效且符合测试规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 17:12:49