using Service.AppSettingModel; namespace WebApi.Test.Application; /// /// AuthApplication 单元测试 /// public class AuthApplicationTest : BaseApplicationTest { private readonly AuthSettings _authSettings; private readonly JwtSettings _jwtSettings; private readonly ILogger _logger; private readonly AuthApplication _application; public AuthApplicationTest() { // 配置测试用的设置 _authSettings = new AuthSettings { Password = "test-password-123" }; _jwtSettings = new JwtSettings { SecretKey = "test-secret-key-minimum-32-characters-long-for-hmacsha256", Issuer = "TestIssuer", Audience = "TestAudience", ExpirationHours = 24 }; var authOptions = Options.Create(_authSettings); var jwtOptions = Options.Create(_jwtSettings); _logger = CreateMockLogger(); _application = new AuthApplication(authOptions, jwtOptions, _logger); } #region Login Tests [Fact] public void Login_有效密码_应返回Token和过期时间() { // Arrange var request = new LoginRequest { Password = "test-password-123" }; // Act var response = _application.Login(request); // Assert response.Should().NotBeNull(); response.Token.Should().NotBeEmpty(); response.ExpiresAt.Should().BeAfter(DateTime.UtcNow); response.ExpiresAt.Should().BeOnOrBefore(DateTime.UtcNow.AddHours(25)); // 允许1小时误差 } [Fact] public void Login_空密码_应抛出ValidationException() { // Arrange var request = new LoginRequest { Password = "" }; // Act & Assert var exception = Assert.Throws(() => _application.Login(request)); exception.Message.Should().Contain("密码不能为空"); } [Fact] public void Login_错误密码_应抛出ValidationException() { // Arrange var request = new LoginRequest { Password = "wrong-password" }; // Act & Assert var exception = Assert.Throws(() => _application.Login(request)); exception.Message.Should().Contain("密码错误"); } [Fact] public void Login_多次调用_应生成不同Token() { // Arrange var request = new LoginRequest { Password = "test-password-123" }; // Act var response1 = _application.Login(request); System.Threading.Thread.Sleep(10); // 确保时间戳不同 var response2 = _application.Login(request); // Assert response1.Token.Should().NotBe(response2.Token); } [Fact] public void Login_生成的Token_应为有效JWT格式() { // Arrange var request = new LoginRequest { Password = "test-password-123" }; // Act var response = _application.Login(request); // Assert response.Token.Should().NotBeEmpty(); var parts = response.Token.Split('.'); parts.Should().HaveCount(3); // JWT格式: header.payload.signature } [Fact] public void Login_成功登录_应记录日志() { // Arrange var request = new LoginRequest { Password = "test-password-123" }; // Act _application.Login(request); // Assert // 验证LogInformation被调用过 _logger.Received().Log( LogLevel.Information, Arg.Any(), Arg.Is(o => o.ToString()!.Contains("登录成功")), Arg.Any(), Arg.Any>()! ); } [Fact] public void Login_密码错误_应记录警告日志() { // Arrange var request = new LoginRequest { Password = "wrong-password" }; // Act try { _application.Login(request); } catch (ValidationException) { // 预期异常 } // Assert // 验证LogWarning被调用过 _logger.Received().Log( LogLevel.Warning, Arg.Any(), Arg.Is(o => o.ToString()!.Contains("密码错误")), Arg.Any(), Arg.Any>()! ); } #endregion }