153 lines
4.3 KiB
C#
153 lines
4.3 KiB
C#
using Service.AppSettingModel;
|
|
|
|
namespace WebApi.Test.Application;
|
|
|
|
/// <summary>
|
|
/// AuthApplication 单元测试
|
|
/// </summary>
|
|
public class AuthApplicationTest : BaseApplicationTest
|
|
{
|
|
private readonly AuthSettings _authSettings;
|
|
private readonly JwtSettings _jwtSettings;
|
|
private readonly ILogger<AuthApplication> _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<AuthApplication>();
|
|
|
|
_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<ValidationException>(() => _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<ValidationException>(() => _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<EventId>(),
|
|
Arg.Is<object>(o => o.ToString()!.Contains("登录成功")),
|
|
Arg.Any<Exception>(),
|
|
Arg.Any<Func<object, Exception?, string>>()!
|
|
);
|
|
}
|
|
|
|
[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<EventId>(),
|
|
Arg.Is<object>(o => o.ToString()!.Contains("密码错误")),
|
|
Arg.Any<Exception>(),
|
|
Arg.Any<Func<object, Exception?, string>>()!
|
|
);
|
|
}
|
|
|
|
#endregion
|
|
}
|