Compare commits
No commits in common. "feb1a733cd72827d2b5b6c5b355b2151b9e2ab5f" and "7bf4c41e4105d0609405d116fa3e91f43d0547de" have entirely different histories.
feb1a733cd
...
7bf4c41e41
@ -50,7 +50,7 @@ jobs:
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
dockerfile: ./src/Dockerfile
|
||||
dockerfile: src/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
@ -1,109 +0,0 @@
|
||||
# 架构
|
||||
|
||||
**分析日期:** 2026-02-28
|
||||
|
||||
## 模式概述
|
||||
|
||||
**整体:** 分层架构 + 领域驱动设计 (DDD)
|
||||
|
||||
**关键特性:**
|
||||
- **控制器层 (Controllers)** - 处理 HTTP 请求,返回 API 响应
|
||||
- **服务层 (Services)** - 业务逻辑实现,使用依赖注入
|
||||
- **数据访问层** - 通过 Entity Framework Core 访问数据库
|
||||
- **领域模型** - 来自外部 Domain 程序集 (Fengling.Platform.Domain)
|
||||
|
||||
## 层次
|
||||
|
||||
**控制器层 (Controllers):**
|
||||
- 位置:`src/Controllers/`
|
||||
- 包含:`UsersController.cs`, `RolesController.cs`, `TenantsController.cs`, `OAuthClientsController.cs`, `GatewayController.cs`
|
||||
- 职责:处理 HTTP 请求、参数验证、返回响应
|
||||
- 依赖:Service 层接口
|
||||
|
||||
**服务层 (Services):**
|
||||
- 位置:`src/Services/`
|
||||
- 包含:`UserService.cs`, `RoleService.cs`, `TenantService.cs`, `OAuthClientService.cs`, `GatewayService.cs`, `H5LinkService.cs`
|
||||
- 职责:业务逻辑实现、数据转换、事务管理
|
||||
- 依赖:Domain 模型、DbContext、UserManager、RoleManager
|
||||
|
||||
**数据层 (Data/Infrastructure):**
|
||||
- PlatformDbContext - 平台业务数据
|
||||
- GatewayDbContext - 网关配置数据
|
||||
- 仓储模式:通过 NetCorePal.Extensions.Repository
|
||||
|
||||
**领域层 (Domain - 外部引用):**
|
||||
- Fengling.Platform.Domain.AggregatesModel.UserAggregate
|
||||
- Fengling.Platform.Domain.AggregatesModel.RoleAggregate
|
||||
- Fengling.Platform.Domain.AggregatesModel.TenantAggregate
|
||||
|
||||
## 数据流
|
||||
|
||||
**典型请求流程:**
|
||||
|
||||
1. **HTTP 请求** → Controller 接收
|
||||
2. **参数验证** → DTO 绑定
|
||||
3. **业务处理** → Service 层执行
|
||||
4. **数据持久化** → EF Core 保存
|
||||
5. **响应返回** → Controller 返回结果
|
||||
|
||||
**状态管理:**
|
||||
- 无状态 API 设计
|
||||
- 状态存储在 PostgreSQL 数据库
|
||||
- 认证状态通过 JWT Token 传递
|
||||
|
||||
## 关键抽象
|
||||
|
||||
**服务接口:**
|
||||
- `IUserService` - 用户管理
|
||||
- `IRoleService` - 角色管理
|
||||
- `ITenantService` - 租户管理
|
||||
- `IOAuthClientService` - OAuth 客户端管理
|
||||
- `IGatewayService` - 网关配置
|
||||
- `IH5LinkService` - H5 链接服务
|
||||
|
||||
**数据传输对象 (DTO):**
|
||||
- 位置:`src/Models/Dtos/`
|
||||
- 模式:CreateXxxDto, UpdateXxxDto, XxxDto, XxxQueryDto
|
||||
- 用途:API 请求/响应数据结构
|
||||
|
||||
## 入口点
|
||||
|
||||
**主入口:**
|
||||
- 位置:`src/Program.cs`
|
||||
- 触发:应用启动时执行
|
||||
- 职责:服务注册、中间件配置、管道构建
|
||||
|
||||
**API 端点:**
|
||||
- `/api/console/[controller]` - RESTful API 前缀
|
||||
- `/swagger` - API 文档
|
||||
|
||||
## 错误处理
|
||||
|
||||
**策略:**
|
||||
- 异常捕获 + 日志记录
|
||||
- 返回标准 HTTP 状态码
|
||||
- 错误详情通过响应体返回
|
||||
|
||||
**模式:**
|
||||
```csharp
|
||||
try {
|
||||
// 业务逻辑
|
||||
} catch (KeyNotFoundException ex) {
|
||||
return NotFound();
|
||||
} catch (InvalidOperationException ex) {
|
||||
return BadRequest();
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError(ex, "...");
|
||||
return StatusCode(500);
|
||||
}
|
||||
```
|
||||
|
||||
## 跨领域关注
|
||||
|
||||
**日志:** Microsoft.Extensions.Logging + ILogger<T>
|
||||
**验证:** ASP.NET Core Model Validation + FluentValidation (已引用)
|
||||
**认证:** OpenIddict + JWT Bearer
|
||||
|
||||
---
|
||||
|
||||
*架构分析:2026-02-28*
|
||||
@ -1,75 +0,0 @@
|
||||
# 代码库问题
|
||||
|
||||
**分析日期:** 2026-02-28
|
||||
|
||||
## 技术债务
|
||||
|
||||
**硬编码密钥:**
|
||||
- 问题:`src/Program.cs:62` 包含硬编码的 OAuth 客户端密钥
|
||||
- 影响:安全风险,不适合生产环境
|
||||
- 修复:使用环境变量或密钥管理服务
|
||||
|
||||
**缺少测试项目:**
|
||||
- 问题:当前项目没有测试目录
|
||||
- 影响:无法进行自动化测试,难以保证代码质量
|
||||
- 修复:添加 xUnit/MSTest 测试项目
|
||||
|
||||
## 已知问题
|
||||
|
||||
**当前未发现严重 Bug:**
|
||||
- 代码结构清晰,异常处理完善
|
||||
|
||||
## 安全考虑
|
||||
|
||||
**OAuth 密钥硬编码:**
|
||||
- 风险:生产环境密钥泄露风险
|
||||
- 当前缓解:仅在开发环境使用
|
||||
- 建议:使用环境变量或密钥 vault
|
||||
|
||||
**CORS 允许所有:**
|
||||
- 风险:`policy.AllowAnyOrigin()` 存在安全风险
|
||||
- 当前缓解:仅开发环境使用
|
||||
- 建议:生产环境限制具体域名
|
||||
|
||||
## 性能问题
|
||||
|
||||
**当前未发现明显性能瓶颈:**
|
||||
- 使用 Entity Framework Core 进行数据库查询
|
||||
- 支持分页查询,避免大数据量返回
|
||||
|
||||
## 脆弱区域
|
||||
|
||||
**审计日志记录:**
|
||||
- 每次操作都写入审计日志
|
||||
- 高并发场景可能成为瓶颈
|
||||
- 建议:考虑异步写入或批量处理
|
||||
|
||||
## 扩展限制
|
||||
|
||||
**当前架构支持:**
|
||||
- 水平扩展:通过 Docker 容器化易于扩展
|
||||
- 功能扩展:分层架构便于添加新模块
|
||||
|
||||
## 依赖风险
|
||||
|
||||
**外部依赖:**
|
||||
- NetCorePal.Extensions - 自定义扩展库
|
||||
- OpenIddict - 社区维护的开源库
|
||||
- 建议:关注版本更新,及时升级
|
||||
|
||||
## 缺失功能
|
||||
|
||||
**缺失测试覆盖:**
|
||||
- 无单元测试
|
||||
- 无集成测试
|
||||
- 无 API 测试
|
||||
- 优先级:高
|
||||
|
||||
**缺失功能:**
|
||||
- 无缓存层(Redis 已引用但未使用)
|
||||
- 无消息队列集成
|
||||
- 无后台任务系统
|
||||
|
||||
---
|
||||
|
||||
*问题审计:2026-02-28*
|
||||
@ -1,118 +0,0 @@
|
||||
# 编码规范
|
||||
|
||||
**分析日期:** 2026-02-28
|
||||
|
||||
## 命名模式
|
||||
|
||||
**文件:**
|
||||
- PascalCase:`UserService.cs`、`UsersController.cs`
|
||||
|
||||
**类/接口:**
|
||||
- PascalCase:`UserService`、`IUserService`
|
||||
|
||||
**方法:**
|
||||
- PascalCase:`GetUsersAsync`、`CreateUserAsync`
|
||||
|
||||
**变量:**
|
||||
- camelCase:`userService`、`userName`
|
||||
|
||||
## 代码风格
|
||||
|
||||
**格式化:**
|
||||
- 使用 .editorconfig 或 Rider/VS 默认格式化
|
||||
- 花括号风格:K&R
|
||||
|
||||
**命名空间:**
|
||||
- 层级式:`Fengling.Console.Controllers`
|
||||
|
||||
## 导入组织
|
||||
|
||||
**顺序:**
|
||||
1. System 命名空间
|
||||
2. 项目内部命名空间
|
||||
3. 第三方库
|
||||
|
||||
**示例:**
|
||||
```csharp
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Fengling.Console.Services;
|
||||
using Fengling.Platform.Domain;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
**模式:**
|
||||
- 使用 try-catch 捕获异常
|
||||
- 按异常类型返回不同 HTTP 状态码
|
||||
- 记录日志:`_logger.LogError(ex, "...")`
|
||||
|
||||
**示例:**
|
||||
```csharp
|
||||
try {
|
||||
await _userService.CreateUserAsync(dto);
|
||||
} catch (InvalidOperationException ex) {
|
||||
return BadRequest(new { message = ex.Message });
|
||||
} catch (Exception ex) {
|
||||
_logger.LogError(ex, "Error creating user");
|
||||
return StatusCode(500, new { message = ex.Message });
|
||||
}
|
||||
```
|
||||
|
||||
## 日志
|
||||
|
||||
**框架:** Microsoft.Extensions.Logging + ILogger<T>
|
||||
|
||||
**模式:**
|
||||
```csharp
|
||||
private readonly ILogger<UsersController> _logger;
|
||||
|
||||
_logger.LogError(ex, "Error message");
|
||||
_logger.LogWarning(ex, "Warning message");
|
||||
```
|
||||
|
||||
## 注释
|
||||
|
||||
**何时注释:**
|
||||
- 公开 API 方法使用 XML 文档注释
|
||||
- 复杂业务逻辑添加说明
|
||||
|
||||
**XML 注释示例:**
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 获取用户列表
|
||||
/// </summary>
|
||||
/// <param name="query">分页查询参数</param>
|
||||
/// <returns>分页的用户列表</returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<PagedResultDto<UserDto>>> GetUsers(...)
|
||||
```
|
||||
|
||||
## 函数设计
|
||||
|
||||
**大小:**
|
||||
- 保持方法简洁,单一职责
|
||||
- 复杂逻辑拆分到私有方法
|
||||
|
||||
**参数:**
|
||||
- 使用 DTO 进行参数分组
|
||||
- 异步方法使用 Async 后缀
|
||||
|
||||
**返回值:**
|
||||
- 使用 Task<T> 返回异步结果
|
||||
- 集合使用 IEnumerable<T>
|
||||
|
||||
## 模块设计
|
||||
|
||||
**导出:**
|
||||
- 公开接口:I[Xxx]Service
|
||||
- 实现类:XxxService
|
||||
|
||||
**依赖注入:**
|
||||
- 构造函数注入
|
||||
- 接口+实现配对
|
||||
|
||||
---
|
||||
|
||||
*规范分析:2026-02-28*
|
||||
@ -1,86 +0,0 @@
|
||||
# 外部集成
|
||||
|
||||
**分析日期:** 2026-02-28
|
||||
|
||||
## APIs & 外部服务
|
||||
|
||||
**身份认证:**
|
||||
- **OpenIddict** - OAuth 2.0 / OpenID Connect 身份提供商
|
||||
- 实现:内置 OpenIddict 认证服务器
|
||||
- 客户端:fengling-api
|
||||
- 密钥:fengling-api-secret(硬编码,见 `src/Program.cs:62`)
|
||||
- 发行者:http://localhost:5132/
|
||||
|
||||
**反向代理:**
|
||||
- **YARP (YarpGateway)** - 反向代理网关
|
||||
- 项目引用:`../../fengling-gateway/src/YarpGateway.csproj`
|
||||
- 用于 API 网关和请求转发
|
||||
|
||||
## 数据存储
|
||||
|
||||
**数据库:**
|
||||
- **PostgreSQL** - 主数据库
|
||||
- 连接:`DefaultConnection` (PlatformDbContext)
|
||||
- 连接:`GatewayConnection` (GatewayDbContext)
|
||||
- ORM:Entity Framework Core + Npgsql
|
||||
|
||||
**表结构:**
|
||||
- 用户表 (ApplicationUser)
|
||||
- 角色表 (ApplicationRole)
|
||||
- 租户表 (Tenant)
|
||||
- OAuth 客户端表
|
||||
- 审计日志表 (AuditLog)
|
||||
- 网关配置表
|
||||
|
||||
## 身份认证
|
||||
|
||||
**认证方案:**
|
||||
- OpenIddict Validation (Bearer Token)
|
||||
- JWT Bearer 认证
|
||||
- ASP.NET Core Identity
|
||||
|
||||
**用户管理:**
|
||||
- ASP.NET Core Identity
|
||||
- 支持租户隔离 (TenantInfo)
|
||||
|
||||
## 监控与可观测性
|
||||
|
||||
**日志:**
|
||||
- 使用 Microsoft.Extensions.Logging
|
||||
- 通过 ILogger<T> 注入
|
||||
- 开发环境启用敏感数据日志
|
||||
|
||||
**API 文档:**
|
||||
- Swagger / OpenAPI
|
||||
- 端点:`/swagger/v1/swagger.json`
|
||||
|
||||
## CI/CD & 部署
|
||||
|
||||
**主机:**
|
||||
- Docker 容器化
|
||||
- Dockerfile 位于 `src/Dockerfile`
|
||||
|
||||
**CI/CD 流水线:**
|
||||
- Gitea Actions (`.gitea/workflows/`)
|
||||
- `deploy.yml` - 部署流水线
|
||||
- `docker.yml` - Docker 构建
|
||||
- `build.yml` - 构建流水线
|
||||
|
||||
## 环境配置
|
||||
|
||||
**必需环境变量:**
|
||||
- `ConnectionStrings:DefaultConnection` - 平台数据库连接
|
||||
- `ConnectionStrings:GatewayConnection` - 网关数据库连接
|
||||
|
||||
**配置文件:**
|
||||
- `appsettings.json` - 应用配置
|
||||
- `appsettings.Development.json` - 开发配置
|
||||
|
||||
## Webhooks & 回调
|
||||
|
||||
**无外部 Webhooks:**
|
||||
- 当前无外部系统回调集成
|
||||
|
||||
---
|
||||
|
||||
*集成审计:2026-02-28*
|
||||
@ -1,86 +0,0 @@
|
||||
# 技术栈
|
||||
|
||||
**分析日期:** 2026-02-28
|
||||
|
||||
## 语言
|
||||
|
||||
**主要:**
|
||||
- **C#** (.NET 10.0) - 后端 API 开发
|
||||
|
||||
**次要:**
|
||||
- **JSON** - 配置文件和数据交换格式
|
||||
|
||||
## 运行时
|
||||
|
||||
**环境:**
|
||||
- .NET 10.0.103 SDK
|
||||
- ASP.NET Core 10.0 Web 应用
|
||||
|
||||
**包管理:**
|
||||
- NuGet
|
||||
- `global.json` 指定 SDK 版本 10.0.103,rollForward: latestMinor
|
||||
|
||||
## 框架
|
||||
|
||||
**核心:**
|
||||
- **ASP.NET Core 10.0** - Web 框架
|
||||
- **Entity Framework Core** - ORM,用于数据访问
|
||||
- **Npgsql.EntityFrameworkCore.PostgreSQL** - PostgreSQL 数据库驱动
|
||||
|
||||
**身份认证:**
|
||||
- **OpenIddict** - OAuth 2.0 / OIDC 身份提供商
|
||||
- **Microsoft.AspNetCore.Authentication.JwtBearer** - JWT 令牌认证
|
||||
|
||||
**其他:**
|
||||
- **Swashbuckle.AspNetCore** - Swagger/OpenAPI 文档
|
||||
- **QRCoder** + **SkiaSharp** - 二维码生成
|
||||
- **NetCorePal.Extensions** - 扩展库集合
|
||||
|
||||
## 关键依赖
|
||||
|
||||
**核心业务:**
|
||||
- `Npgsql.EntityFrameworkCore.PostgreSQL` - PostgreSQL 数据库访问
|
||||
- `OpenIddict.*` - 身份认证和授权
|
||||
- `Microsoft.AspNetCore.Identity.EntityFrameworkCore` - 用户身份管理
|
||||
|
||||
**扩展库:**
|
||||
- `NetCorePal.Extensions.AspNetCore` - ASP.NET Core 扩展
|
||||
- `NetCorePal.Extensions.DistributedLocks.Redis` - 分布式锁
|
||||
- `NetCorePal.Extensions.Repository.EntityFrameworkCore` - 仓储模式
|
||||
|
||||
**工具库:**
|
||||
- `Swashbuckle.AspNetCore` - API 文档
|
||||
- `QRCoder` + `SkiaSharp` - 二维码生成
|
||||
- `Microsoft.OpenApi` - OpenAPI 支持
|
||||
|
||||
## 项目引用
|
||||
|
||||
- `YarpGateway` - 反向代理网关
|
||||
- `Fengling.Platform.Infrastructure` - 平台基础设施
|
||||
|
||||
## 配置
|
||||
|
||||
**环境配置:**
|
||||
- `appsettings.json` - 默认配置
|
||||
- `appsettings.Development.json` - 开发环境配置
|
||||
- `launchSettings.json` - 启动配置
|
||||
|
||||
**数据库连接:**
|
||||
- `DefaultConnection` - 平台数据库 (PlatformDbContext)
|
||||
- `GatewayConnection` - 网关数据库 (GatewayDbContext)
|
||||
|
||||
## 平台要求
|
||||
|
||||
**开发:**
|
||||
- .NET 10.0 SDK
|
||||
- PostgreSQL 数据库
|
||||
- Visual Studio Code / Rider / Visual Studio
|
||||
|
||||
**生产:**
|
||||
- Docker 容器化部署
|
||||
- Linux 服务器
|
||||
- PostgreSQL 数据库
|
||||
|
||||
---
|
||||
|
||||
*技术栈分析:2026-02-28*
|
||||
@ -1,96 +0,0 @@
|
||||
# 代码库结构
|
||||
|
||||
**分析日期:** 2026-02-28
|
||||
|
||||
## 目录布局
|
||||
|
||||
```
|
||||
fengling-console/
|
||||
├── global.json # .NET SDK 版本配置
|
||||
├── Directory.Build.props # 项目共享属性
|
||||
├── src/
|
||||
│ ├── Fengling.Console.csproj # 主项目文件
|
||||
│ ├── Program.cs # 应用入口
|
||||
│ ├── Dockerfile # Docker 构建文件
|
||||
│ ├── appsettings.json # 应用配置
|
||||
│ ├── appsettings.Development.json # 开发环境配置
|
||||
│ ├── Properties/
|
||||
│ │ └── launchSettings.json # 启动配置
|
||||
│ ├── Controllers/ # API 控制器
|
||||
│ ├── Services/ # 业务服务层
|
||||
│ ├── Models/
|
||||
│ │ └── Dtos/ # 数据传输对象
|
||||
│ └── bin/Debug/ # 编译输出
|
||||
├── .gitea/workflows/ # CI/CD 流水线
|
||||
```
|
||||
|
||||
## 目录用途
|
||||
|
||||
**src/Controllers/:**
|
||||
- 用途:API 端点定义
|
||||
- 包含文件:
|
||||
- `UsersController.cs` - 用户管理 API
|
||||
- `RolesController.cs` - 角色管理 API
|
||||
- `TenantsController.cs` - 租户管理 API
|
||||
- `OAuthClientsController.cs` - OAuth 客户端 API
|
||||
- `GatewayController.cs` - 网关配置 API
|
||||
- `GlobalUsing.cs` - 全局 using 指令
|
||||
|
||||
**src/Services/:**
|
||||
- 用途:业务逻辑实现
|
||||
- 包含文件:
|
||||
- `UserService.cs` - 用户业务逻辑
|
||||
- `RoleService.cs` - 角色业务逻辑
|
||||
- `TenantService.cs` - 租户业务逻辑
|
||||
- `OAuthClientService.cs` - OAuth 客户端逻辑
|
||||
- `GatewayService.cs` - 网关配置逻辑
|
||||
- `H5LinkService.cs` - H5 链接服务
|
||||
|
||||
**src/Models/Dtos/:**
|
||||
- 用途:API 数据传输对象
|
||||
- 包含文件:
|
||||
- CreateXxxDto.cs (CreateUserDto, CreateRoleDto, CreateTenantDto, CreateClientDto)
|
||||
- UpdateXxxDto.cs (UpdateUserDto, UpdateRoleDto, UpdateTenantDto, UpdateClientDto)
|
||||
- XxxDto.cs (UserDto, RoleDto, TenantDto, OAuthClientDto, GatewayDto)
|
||||
- XxxQueryDto.cs (UserQueryDto, RoleQueryDto, TenantQueryDto, OAuthClientQueryDto)
|
||||
- `PaginationDto.cs` - 分页结果
|
||||
- `ResetPasswordDto.cs` - 密码重置
|
||||
- `TenantSettingsDto.cs` - 租户设置
|
||||
|
||||
## 关键文件位置
|
||||
|
||||
**入口点:**
|
||||
- `src/Program.cs` - 应用启动配置和服务注册
|
||||
|
||||
**配置:**
|
||||
- `src/appsettings.json` - 应用配置
|
||||
- `src/appsettings.Development.json` - 开发环境配置
|
||||
|
||||
**核心逻辑:**
|
||||
- `src/Services/UserService.cs` - 用户服务实现
|
||||
- `src/Controllers/UsersController.cs` - 用户 API
|
||||
|
||||
## 命名约定
|
||||
|
||||
**文件:**
|
||||
- PascalCase:`UserService.cs`、`UsersController.cs`
|
||||
|
||||
**目录:**
|
||||
- PascalCase:`Controllers/`、`Services/`、`Models/Dtos/`
|
||||
|
||||
**类/接口:**
|
||||
- PascalCase:`UserService`、`IUserService`
|
||||
|
||||
## 新增代码位置
|
||||
|
||||
**新增功能:**
|
||||
- API 端点:`src/Controllers/`
|
||||
- 业务逻辑:`src/Services/`
|
||||
- DTO:`src/Models/Dtos/`
|
||||
|
||||
**新增测试:**
|
||||
- 建议位置:单独的测试项目(如 `tests/` 目录)
|
||||
|
||||
---
|
||||
|
||||
*结构分析:2026-02-28*
|
||||
@ -1,144 +0,0 @@
|
||||
# 测试模式
|
||||
|
||||
**分析日期:** 2026-02-28
|
||||
|
||||
## 测试框架
|
||||
|
||||
**未检测到测试框架:**
|
||||
- 当前项目未包含测试项目
|
||||
- 建议添加 xUnit、NUnit 或 MSTest
|
||||
|
||||
**推荐配置:**
|
||||
- 框架:xUnit
|
||||
- Mock 库:Moq
|
||||
- 集成测试:Microsoft.AspNetCore.Mvc.Testing
|
||||
|
||||
## 测试文件组织
|
||||
|
||||
**建议结构:**
|
||||
```
|
||||
tests/
|
||||
├── Fengling.Console.Tests/
|
||||
│ ├── Unit/
|
||||
│ │ ├── Services/
|
||||
│ │ └── Controllers/
|
||||
│ └── Integration/
|
||||
```
|
||||
|
||||
## 测试结构
|
||||
|
||||
**单元测试示例:**
|
||||
```csharp
|
||||
public class UserServiceTests
|
||||
{
|
||||
private readonly Mock<UserManager<ApplicationUser>> _userManagerMock;
|
||||
private readonly UserService _userService;
|
||||
|
||||
public UserServiceTests()
|
||||
{
|
||||
_userManagerMock = new Mock<UserManager<ApplicationUser>>(...);
|
||||
_userService = new UserService(...);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetUsersAsync_ReturnsPagedResults()
|
||||
{
|
||||
// Arrange
|
||||
var expectedUsers = new List<UserDto> { ... };
|
||||
|
||||
// Act
|
||||
var result = await _userService.GetUsersAsync(1, 10);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedUsers.Count, result.TotalCount);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 模拟 (Mocking)
|
||||
|
||||
**常用 Mock 库:**
|
||||
- Moq - 主流 Mock 框架
|
||||
|
||||
**Mock 对象:**
|
||||
```csharp
|
||||
var mockUserManager = new Mock<UserManager<ApplicationUser>>(
|
||||
store: mockStore.Object,
|
||||
optionsAccessor: new Mock<IOptions<IdentityOptions>>().Object,
|
||||
passwordHasher: new Mock<IPasswordHasher<ApplicationUser>>().Object,
|
||||
validators: new List<IUserValidator<ApplicationUser>>(),
|
||||
keyNormalizer: new Mock<ILookupNormalizer>().Object,
|
||||
errors: new IdentityErrorDescriber(),
|
||||
logger: new Mock<ILogger<UserManager<ApplicationUser>>>().Object,
|
||||
services: new Mock<IServiceProvider>().Object);
|
||||
```
|
||||
|
||||
## Fixture 和工厂
|
||||
|
||||
**测试数据:**
|
||||
- 使用静态工厂方法创建测试数据
|
||||
- 每个测试方法独立,不共享状态
|
||||
|
||||
**示例:**
|
||||
```csharp
|
||||
public static class TestData
|
||||
{
|
||||
public static CreateUserDto CreateValidUserDto() => new CreateUserDto
|
||||
{
|
||||
UserName = "testuser",
|
||||
Email = "test@example.com",
|
||||
Password = "Test@123456",
|
||||
RealName = "Test User"
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 测试类型
|
||||
|
||||
**单元测试:**
|
||||
- 范围:Service 层业务逻辑
|
||||
- 重点:边界条件、异常处理
|
||||
|
||||
**集成测试:**
|
||||
- 范围:Controller API 端点
|
||||
- 使用:Microsoft.AspNetCore.Mvc.Testing
|
||||
|
||||
## 常见模式
|
||||
|
||||
**异步测试:**
|
||||
```csharp
|
||||
[Fact]
|
||||
public async Task CreateUserAsync_ValidInput_ReturnsCreatedUser()
|
||||
{
|
||||
// Arrange
|
||||
var dto = TestData.CreateValidUserDto();
|
||||
|
||||
// Act
|
||||
var result = await _userService.CreateUserAsync(dto);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(dto.UserName, result.UserName);
|
||||
}
|
||||
```
|
||||
|
||||
**异常测试:**
|
||||
```csharp
|
||||
[Fact]
|
||||
public async Task CreateUserAsync_DuplicateUser_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var dto = TestData.CreateValidUserDto();
|
||||
_userManagerMock
|
||||
.Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()))
|
||||
.ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "Duplicate" }));
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
_userService.CreateUserAsync(dto));
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*测试分析:2026-02-28*
|
||||
Loading…
Reference in New Issue
Block a user