using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Moq; using VendingMachine.Application.DTOs.User; using VendingMachine.Infrastructure.Data; using VendingMachine.Infrastructure.Services; using Xunit; namespace VendingMachine.Tests; /// /// 用户认证单元测试 /// 需求: 1.1, 1.3, 1.7 /// public class UserServiceTests : IDisposable { private readonly AppDbContext _db; private readonly InMemoryVerificationCodeStore _codeStore; private readonly UserService _userService; public UserServiceTests() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; _db = new AppDbContext(options); _codeStore = new InMemoryVerificationCodeStore(); var config = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { ["Jwt:Secret"] = "TestSecretKeyForUnitTesting_AtLeast32Characters!", ["Jwt:Issuer"] = "Test", ["Jwt:Audience"] = "Test", ["Jwt:ExpirationMinutes"] = "60" }) .Build(); var logger = new Mock>(); _userService = new UserService(_db, _codeStore, config, logger.Object); } /// /// 测试发送验证码成功 - 需求 1.1 /// [Fact] public async Task SendVerificationCode_ValidInput_ShouldSucceed() { var result = await _userService.SendVerificationCodeAsync( new SendCodeRequest { Phone = "912345678", AreaCode = "+886" }); Assert.True(result.Success); Assert.Single(_codeStore.Store); } /// /// 测试发送验证码 - 无效区号 /// [Fact] public async Task SendVerificationCode_InvalidAreaCode_ShouldFail() { var result = await _userService.SendVerificationCodeAsync( new SendCodeRequest { Phone = "912345678", AreaCode = "886" }); Assert.False(result.Success); } /// /// 测试登录成功流程 - 需求 1.3 /// [Fact] public async Task Login_ValidCode_ShouldSucceed() { await _userService.SendVerificationCodeAsync( new SendCodeRequest { Phone = "912345678", AreaCode = "+886" }); var storedCode = _codeStore.Store.Values.First(); var result = await _userService.LoginAsync(new LoginRequest { Phone = "912345678", AreaCode = "+886", Code = storedCode, AgreementAccepted = true }); Assert.True(result.Success); Assert.NotNull(result.Data); Assert.NotEmpty(result.Data!.Token); Assert.Equal("912345678", result.Data.UserInfo.Phone); } /// /// 测试登录失败 - 验证码错误 - 需求 1.3 /// [Fact] public async Task Login_WrongCode_ShouldFail() { await _userService.SendVerificationCodeAsync( new SendCodeRequest { Phone = "912345678", AreaCode = "+886" }); var result = await _userService.LoginAsync(new LoginRequest { Phone = "912345678", AreaCode = "+886", Code = "000000", AgreementAccepted = true }); Assert.False(result.Success); Assert.Contains("验证码", result.Message); } /// /// 测试登录失败 - 未勾选协议 /// [Fact] public async Task Login_AgreementNotAccepted_ShouldFail() { var result = await _userService.LoginAsync(new LoginRequest { Phone = "912345678", AreaCode = "+886", Code = "123456", AgreementAccepted = false }); Assert.False(result.Success); Assert.Contains("协议", result.Message); } /// /// 测试注销账号流程 - 需求 1.7 /// [Fact] public async Task DeleteAccount_ExistingUser_ShouldSoftDelete() { await _userService.SendVerificationCodeAsync( new SendCodeRequest { Phone = "912345678", AreaCode = "+886" }); var storedCode = _codeStore.Store.Values.First(); var loginResult = await _userService.LoginAsync(new LoginRequest { Phone = "912345678", AreaCode = "+886", Code = storedCode, AgreementAccepted = true }); var uid = loginResult.Data!.UserInfo.Uid; var deleteResult = await _userService.DeleteAccountAsync(uid); Assert.True(deleteResult.Success); Assert.Contains("已注销", deleteResult.Message); // 注销后应无法获取用户信息 var infoResult = await _userService.GetUserInfoAsync(uid); Assert.False(infoResult.Success); } public void Dispose() { _db.Dispose(); } }