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

.NET Core中无需配置IService Mock IOptions读取secret.json的Xunit测试方案

实现方案

你不需要在测试项目中配置依赖注入服务容器,直接手动构造控制器所有依赖的模拟/测试实例,再实例化SeedController执行测试逻辑即可,具体实现步骤如下:

前置依赖

先安装测试所需NuGet包:

  • xunit
  • Moq
  • Microsoft.EntityFrameworkCore.InMemory
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore
  • Microsoft.Extensions.Options

测试代码示例

using Xunit;
using Moq;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Hosting;
// 替换为你自己的项目命名空间
using YourProjectNamespace.Data;
using YourProjectNamespace.Controllers;
using YourProjectNamespace.Models;

namespace YourProjectNamespace.Tests;

public class SeedControllerTests
{
    // 构造测试用的默认用户配置
    private readonly DefaultUserOptions _testOptions = new()
    {
        Admin_Email = "admin@test.com",
        Admin_Password = "Test@123456",
        User_Email = "user@test.com",
        User_Password = "Test@123456"
    };

    [Fact]
    public async Task CreateDefaultUsers_FirstRun_AddsTwoUsers()
    {
        // 1. 构造内存数据库的DbContext,无需真实数据库
        var dbOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .Options;
        using var context = new ApplicationDbContext(dbOptions);

        // 2. 构造Mock的RoleManager
        var roleStoreMock = new Mock<IRoleStore<IdentityRole>>();
        var roleManager = new RoleManager<IdentityRole>(roleStoreMock.Object, null, null, null, null);
        // 模拟首次查询角色不存在
        roleStoreMock.Setup(x => x.FindByNameAsync("RegisteredUser", CancellationToken.None))
            .ReturnsAsync((IdentityRole)null);
        roleStoreMock.Setup(x => x.FindByNameAsync("Administrator", CancellationToken.None))
            .ReturnsAsync((IdentityRole)null);
        roleStoreMock.Setup(x => x.CreateAsync(It.IsAny<IdentityRole>(), CancellationToken.None))
            .ReturnsAsync(IdentityResult.Success);

        // 3. 构造Mock的UserManager
        var userStoreMock = new Mock<IUserStore<ApplicationUser>>();
        // 若测试涉及密码哈希逻辑,可额外Mock IPasswordHasher传入
        var passwordHasherMock = new Mock<IPasswordHasher<ApplicationUser>>();
        passwordHasherMock.Setup(x => x.HashPassword(It.IsAny<ApplicationUser>(), It.IsAny<string>())).Returns("test_hash_value");
        var userManager = new UserManager<ApplicationUser>(userStoreMock.Object, null, passwordHasherMock.Object, null, null, null, null, null, null);
        // 模拟首次查询用户不存在
        userStoreMock.Setup(x => x.FindByNameAsync(_testOptions.Admin_Email, CancellationToken.None))
            .ReturnsAsync((ApplicationUser)null);
        userStoreMock.Setup(x => x.FindByNameAsync(_testOptions.User_Email, CancellationToken.None))
            .ReturnsAsync((ApplicationUser)null);
        userStoreMock.Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>(), CancellationToken.None))
            .ReturnsAsync(IdentityResult.Success);
        userStoreMock.Setup(x => x.AddToRoleAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>(), CancellationToken.None))
            .ReturnsAsync(IdentityResult.Success);
        userStoreMock.Setup(x => x.UpdateAsync(It.IsAny<ApplicationUser>(), CancellationToken.None))
            .ReturnsAsync(IdentityResult.Success);

        // 4. 构造Mock的IWebHostEnvironment(现有代码未用到该依赖,直接构造空实例即可)
        var envMock = new Mock<IWebHostEnvironment>();

        // 5. 构造IOptions配置实例
        var options = Options.Create(_testOptions);

        // 6. 手动实例化控制器,完全不需要依赖DI容器
        var controller = new SeedController(context, roleManager, userManager, envMock.Object, options);

        // 7. 执行测试方法
        var result = await controller.CreateDefaultUsers();

        // 8. 断言结果符合预期
        var jsonResult = Assert.IsType<JsonResult>(result);
        dynamic resultData = jsonResult.Value;
        Assert.Equal(2, resultData.Count);

        // 验证核心方法调用次数符合预期
        roleStoreMock.Verify(x => x.CreateAsync(It.Is<IdentityRole>(r => r.Name == "RegisteredUser"), CancellationToken.None), Times.Once);
        roleStoreMock.Verify(x => x.CreateAsync(It.Is<IdentityRole>(r => r.Name == "Administrator"), CancellationToken.None), Times.Once);
        userStoreMock.Verify(x => x.CreateAsync(It.Is<ApplicationUser>(u => u.Email == _testOptions.Admin_Email), _testOptions.Admin_Password, CancellationToken.None), Times.Once);
        userStoreMock.Verify(x => x.CreateAsync(It.Is<ApplicationUser>(u => u.Email == _testOptions.User_Email), _testOptions.User_Password, CancellationToken.None), Times.Once);
    }

    [Fact]
    public async Task CreateDefaultUsers_UsersExist_ReturnsZeroCount()
    {
        // 1. 构造内存数据库的DbContext
        var dbOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
            .Options;
        using var context = new ApplicationDbContext(dbOptions);

        // 2. 构造Mock的RoleManager,模拟角色已存在
        var roleStoreMock = new Mock<IRoleStore<IdentityRole>>();
        var roleManager = new RoleManager<IdentityRole>(roleStoreMock.Object, null, null, null, null);
        roleStoreMock.Setup(x => x.FindByNameAsync(It.IsAny<string>(), CancellationToken.None))
            .ReturnsAsync(new IdentityRole());

        // 3. 构造Mock的UserManager,模拟用户已存在
        var userStoreMock = new Mock<IUserStore<ApplicationUser>>();
        var passwordHasherMock = new Mock<IPasswordHasher<ApplicationUser>>();
        var userManager = new UserManager<ApplicationUser>(userStoreMock.Object, null, passwordHasherMock.Object, null, null, null, null, null, null);
        userStoreMock.Setup(x => x.FindByNameAsync(It.IsAny<string>(), CancellationToken.None))
            .ReturnsAsync(new ApplicationUser());

        // 4. 构造其他依赖
        var envMock = new Mock<IWebHostEnvironment>();
        var options = Options.Create(_testOptions);

        // 5. 实例化控制器
        var controller = new SeedController(context, roleManager, userManager, envMock.Object, options);

        // 6. 执行测试
        var result = await controller.CreateDefaultUsers();
        var jsonResult = Assert.IsType<JsonResult>(result);
        dynamic resultData = jsonResult.Value;

        // 7. 断言没有新增用户
        Assert.Equal(0, resultData.Count);
        userStoreMock.Verify(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>(), CancellationToken.None), Times.Never);
    }
}

说明

  • 所有依赖项均为手动构造或通过Moq模拟,完全不需要配置IServiceCollection服务容器,符合你的测试要求
  • 测试覆盖了首次执行播种和重复执行播种两个核心场景,你可以根据自身需求扩展其他测试用例
  • 如果不需要完全隔离测试,也可以替换掉Mock的RoleManager和UserManager,用内存数据库配合真实的Identity存储实现更贴近生产环境的测试逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 06:57:03