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

如何在XUnit中从Header取Token并Mock服务类测试控制器

XUnit测试API:Mock服务类与Token问题解决方案

一、先修复业务代码中的潜在错误

你的代码里有几处大小写不匹配和空引用风险点,这会直接导致测试失败:

  1. AdditionService中给AdditionDto赋值时,httpCode应改为**HttpCode**(属性定义是大写H)
  2. 控制器里判断result.Httpcode需改为**result.HttpCode**
  3. 解析Claim时,FirstOrDefault()后直接ToString()会导致空引用,需先判断Claim是否存在

二、用Moq实现IAdditionService的Mock

测试时使用Moq框架Mock服务接口,步骤如下:

1. 安装依赖包

先安装必要的NuGet包:

  • xunit
  • Moq
  • Microsoft.AspNetCore.Mvc.Core

2. 完整测试类示例

using Xunit;
using Moq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;

public class AdditionControllerTests
{
    private readonly Mock<IAddtionService> _mockService;
    private readonly AdditionController _controller;

    public AdditionControllerTests()
    {
        // 初始化Mock服务
        _mockService = new Mock<IAddtionService>();
        _controller = new AdditionController(_mockService.Object);

        // 模拟HttpContext,设置请求Header与用户身份
        var httpContext = new DefaultHttpContext();
        // 添加Authorization Header
        httpContext.Request.Headers["Authorization"] = "Bearer dummy-token";
        // 模拟已解析的用户Claim,避免测试中真的解析JWT
        var user = new ClaimsPrincipal(new ClaimsIdentity(new[]
        {
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "test-user"),
            new Claim(ClaimTypes.Role, "Admin") // 满足[Authorize(Roles = "Admin")]要求
        }, "Bearer"));
        
        _controller.ControllerContext = new ControllerContext
        {
            HttpContext = httpContext,
            User = user
        };
    }

    [Fact]
    public void AddTwoNumbers_ValidInputs_ReturnsOk()
    {
        // Arrange
        int input1 = 2, input2 = 3;
        string userName = "test-user";
        var expectedDto = new AdditionDto
        {
            HttpCode = 200,
            UserName = userName,
            Total = 5
        };

        // 设置Mock服务的返回逻辑
        _mockService.Setup(s => s.AddingTwoNumbers(input1, input2, userName))
                    .Returns(expectedDto);

        // Act
        var result = _controller.AddTwoNumbers(input1, input2);

        // Assert
        var okResult = Assert.IsType<OkObjectResult>(result);
        var returnedDto = Assert.IsType<AdditionDto>(okResult.Value);
        Assert.Equal(expectedDto.Total, returnedDto.Total);
        // 验证Mock方法是否被正确调用
        _mockService.Verify(s => s.AddingTwoNumbers(input1, input2, userName), Times.Once);
    }

    [Fact]
    public void AddTwoNumbers_InvalidModelState_ReturnsBadRequest()
    {
        // Arrange:手动添加模型错误
        _controller.ModelState.AddModelError("input1", "输入不能为空");

        // Act
        var result = _controller.AddTwoNumbers(0, 0);

        // Assert
        Assert.IsType<BadRequestResult>(result);
    }
}

三、优化控制器的Token解析逻辑(避免空引用)

把控制器中Token解析的代码改为以下形式,从根源避免空引用异常:

public IActionResult AddTwoNumbers(int input1, int input2)
{
    if (!ModelState.IsValid)
        return BadRequest();

    var authHeader = HttpContext.Request.Headers["Authorization"].ToString();
    if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))
        return Unauthorized("无效的授权头");

    var tokenParts = authHeader.Split(' ');
    if (tokenParts.Length < 2)
        return BadRequest("授权头格式错误");

    var handler = new JwtSecurityTokenHandler();
    if (!handler.CanReadToken(tokenParts[1]))
        return BadRequest("无效的Token");

    var decodedToken = handler.ReadJwtToken(tokenParts[1]);
    var nameClaim = decodedToken.Claims.FirstOrDefault(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name");
    if (nameClaim == null)
        return BadRequest("Token中缺少用户名称Claim");

    var result = _additionService.AddingTwoNumbers(input1, input2, nameClaim.Value);
    return result.HttpCode == 200 ? Ok(result) : StatusCode(500, result);
}

四、处理[Authorize]特性的测试

测试时要满足[Authorize(Roles = "Admin")]的要求,只需在模拟用户身份时添加Admin角色即可(如测试类构造函数中所示),无需处理真实的JWT验证流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 14:20:28