using System.Net; using System.Net.Http.Json; using System.Text.Json; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using NSubstitute; using Xunit; using XiangYi.AdminApi; using XiangYi.Application.DTOs.Requests; using XiangYi.Application.DTOs.Responses; using XiangYi.Application.Interfaces; namespace XiangYi.Api.Tests.AdminApi; /// /// 后台系统管理控制器集成测试(管理员、角色、权限、菜单、日志) /// public class AdminSystemControllerIntegrationTests : IClassFixture> { private readonly WebApplicationFactory _factory; private readonly IAdminAccountService _mockAdminAccountService; private readonly IAdminRoleService _mockAdminRoleService; private readonly IAdminMenuService _mockAdminMenuService; private readonly IAdminLogService _mockAdminLogService; public AdminSystemControllerIntegrationTests(WebApplicationFactory factory) { _mockAdminAccountService = Substitute.For(); _mockAdminRoleService = Substitute.For(); _mockAdminMenuService = Substitute.For(); _mockAdminLogService = Substitute.For(); _factory = factory.WithWebHostBuilder(builder => { builder.UseEnvironment("Testing"); builder.ConfigureServices(services => { services.RemoveAll(); services.RemoveAll(); services.RemoveAll(); services.RemoveAll(); services.AddSingleton(_mockAdminAccountService); services.AddSingleton(_mockAdminRoleService); services.AddSingleton(_mockAdminMenuService); services.AddSingleton(_mockAdminLogService); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = AdminTestAuthHandler.AuthenticationScheme; options.DefaultChallengeScheme = AdminTestAuthHandler.AuthenticationScheme; }) .AddScheme( AdminTestAuthHandler.AuthenticationScheme, options => { }); }); }); } #region 管理员管理测试 /// /// 测试获取管理员列表- 未授权返回401 /// [Fact] public async Task GetAdminList_WithoutAuth_ReturnsUnauthorized() { var client = _factory.CreateClient(); var response = await client.GetAsync("/api/admin/admins"); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); } /// /// 测试获取管理员列表- 授权后成功 /// [Fact] public async Task GetAdminList_WithAuth_ReturnsSuccess() { var expectedResult = new PagedResult { Items = new List { new AdminAccountListDto { AdminId = 1, Username = "admin", RealName = "超级管理员", Status = 1, StatusText = "正常", Roles = new List { new AdminRoleDto { RoleId = 1, RoleName = "超级管理员", RoleCode = "admin" } } } }, Total = 1, PageIndex = 1, PageSize = 20 }; _mockAdminAccountService.GetAdminListAsync(Arg.Any()) .Returns(Task.FromResult(expectedResult)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var response = await client.GetAsync("/api/admin/admins"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.NotNull(result.Data); Assert.Single(result.Data.Items); } /// /// 测试创建管理员- 成功 /// [Fact] public async Task CreateAdmin_WithAuth_ReturnsSuccess() { _mockAdminAccountService.CreateAdminAsync(Arg.Any()) .Returns(Task.FromResult(100L)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var request = new CreateAdminAccountRequest { Username = "newadmin", Password = "password123", RealName = "新管理员", Phone = "13800138000", Status = 1, RoleIds = new List { 2 } }; var response = await client.PostAsJsonAsync("/api/admin/admins", request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.Equal(100L, result.Data); } /// /// 测试删除管理员- 成功 /// [Fact] public async Task DeleteAdmin_WithAuth_ReturnsSuccess() { _mockAdminAccountService.DeleteAdminAsync(2, 1) .Returns(Task.FromResult(true)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var response = await client.DeleteAsync("/api/admin/admins/2"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); } #endregion #region 角色管理测试 /// /// 测试获取角色列表 - 成功 /// [Fact] public async Task GetRoleList_WithAuth_ReturnsSuccess() { var expectedResult = new PagedResult { Items = new List { new AdminRoleListDto { RoleId = 1, RoleName = "超级管理员", RoleCode = "admin", Status = 1, StatusText = "正常", UserCount = 1 } }, Total = 1, PageIndex = 1, PageSize = 20 }; _mockAdminRoleService.GetRoleListAsync(Arg.Any()) .Returns(Task.FromResult(expectedResult)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var response = await client.GetAsync("/api/admin/roles"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.NotNull(result.Data); Assert.Single(result.Data.Items); } /// /// 测试创建角色 - 成功 /// [Fact] public async Task CreateRole_WithAuth_ReturnsSuccess() { _mockAdminRoleService.CreateRoleAsync(Arg.Any()) .Returns(Task.FromResult(100L)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var request = new CreateRoleRequest { RoleName = "运营管理员", RoleCode = "operator", Description = "负责运营相关功能", Status = 1 }; var response = await client.PostAsJsonAsync("/api/admin/roles", request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.Equal(100L, result.Data); } /// /// 测试分配角色权限 - 成功 /// [Fact] public async Task AssignRolePermissions_WithAuth_ReturnsSuccess() { _mockAdminRoleService.AssignPermissionsAsync(1, Arg.Any>()) .Returns(Task.FromResult(true)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var request = new AssignRolePermissionsRequest { PermissionIds = new List { 1, 2, 3 } }; var response = await client.PostAsJsonAsync("/api/admin/roles/1/permissions", request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); } #endregion #region 菜单管理测试 /// /// 测试获取菜单树 - 成功 /// [Fact] public async Task GetMenuTree_WithAuth_ReturnsSuccess() { var expectedResult = new List { new AdminMenuTreeDto { MenuId = 1, MenuName = "用户管理", MenuType = 1, MenuTypeText = "目录", Path = "/users", Children = new List { new AdminMenuTreeDto { MenuId = 2, ParentId = 1, MenuName = "用户列表", MenuType = 2, MenuTypeText = "菜单", Path = "/users/list" } } } }; _mockAdminMenuService.GetMenuTreeAsync(Arg.Any()) .Returns(Task.FromResult(expectedResult)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var response = await client.GetAsync("/api/admin/menus"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.NotNull(result.Data); Assert.Single(result.Data); Assert.Single(result.Data[0].Children); } /// /// 测试创建菜单 - 成功 /// [Fact] public async Task CreateMenu_WithAuth_ReturnsSuccess() { _mockAdminMenuService.CreateMenuAsync(Arg.Any()) .Returns(Task.FromResult(100L)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var request = new CreateMenuRequest { ParentId = 0, MenuName = "新菜单", MenuType = 1, Path = "/new", Status = 1 }; var response = await client.PostAsJsonAsync("/api/admin/menus", request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.Equal(100L, result.Data); } #endregion #region 操作日志测试 /// /// 测试获取操作日志列表 - 成功 /// [Fact] public async Task GetLogList_WithAuth_ReturnsSuccess() { var expectedResult = new PagedResult { Items = new List { new AdminLogListDto { LogId = 1, AdminUserId = 1, AdminUsername = "admin", Module = "用户管理", Action = "更新状态", Description = "禁用用户", RequestUrl = "/api/admin/users/1/status", RequestMethod = "PUT", Status = 1, StatusText = "成功", CreateTime = DateTime.Now.AddMinutes(-30) } }, Total = 1, PageIndex = 1, PageSize = 20 }; _mockAdminLogService.GetLogListAsync(Arg.Any()) .Returns(Task.FromResult(expectedResult)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var response = await client.GetAsync("/api/admin/logs"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.NotNull(result.Data); Assert.Single(result.Data.Items); } /// /// 测试获取操作日志详情 - 成功 /// [Fact] public async Task GetLogDetail_WithAuth_ReturnsSuccess() { var expectedResult = new AdminLogDetailDto { LogId = 1, AdminUserId = 1, AdminUsername = "admin", Module = "用户管理", Action = "更新状态", Description = "禁用用户", RequestUrl = "/api/admin/users/1/status", RequestMethod = "PUT", RequestParams = "{\"status\":2}", ResponseResult = "{\"code\":0,\"message\":\"success\"}", Status = 1, StatusText = "成功" }; _mockAdminLogService.GetLogDetailAsync(1) .Returns(Task.FromResult(expectedResult)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var response = await client.GetAsync("/api/admin/logs/1"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.NotNull(result.Data); Assert.Equal(expectedResult.LogId, result.Data.LogId); } #endregion #region 权限管理测试 /// /// 测试获取所有权限- 成功 /// [Fact] public async Task GetAllPermissions_WithAuth_ReturnsSuccess() { var expectedResult = new List { new AdminPermissionGroupDto { Module = "用户管理", Permissions = new List { new AdminPermissionDto { PermissionId = 1, PermissionName = "用户列表", PermissionCode = "user:list", Module = "用户管理" }, new AdminPermissionDto { PermissionId = 2, PermissionName = "用户详情", PermissionCode = "user:view", Module = "用户管理" } } } }; _mockAdminRoleService.GetAllPermissionsAsync() .Returns(Task.FromResult(expectedResult)); var client = _factory.CreateClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer admin-token-1"); var response = await client.GetAsync("/api/admin/permissions"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); Assert.NotNull(result); Assert.Equal(0, result.Code); Assert.NotNull(result.Data); Assert.Single(result.Data); Assert.Equal(2, result.Data[0].Permissions.Count); } #endregion }