using MiAssessment.Core.Interfaces; using MiAssessment.Core.Services; using MiAssessment.Model.Data; using MiAssessment.Model.Models.Auth; using MiAssessment.Model.Models.Payment; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; using Xunit; namespace MiAssessment.Tests.Services; /// /// Mock HttpMessageHandler for testing /// public class MockHttpMessageHandler : HttpMessageHandler { private readonly Func> _handler; public MockHttpMessageHandler(Func> handler) { _handler = handler; } protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { return await _handler(request); } } public class WechatServiceTests { private readonly Mock> _mockLogger; private readonly WechatSettings _wechatSettings; private readonly Mock> _mockWechatPaySettings; private readonly Mock _mockRedisService; public WechatServiceTests() { _mockLogger = new Mock>(); _wechatSettings = new WechatSettings { AppId = "test_app_id", AppSecret = "test_app_secret" }; var wechatPaySettings = new WechatPaySettings { DefaultMerchant = new WechatPayMerchantConfig { Name = "TestMerchant", MchId = "1234567890", AppId = "wx1234567890abcdef", Key = "test_secret_key_32_characters_ok", OrderPrefix = "TST", Weight = 1, NotifyUrl = "https://example.com/notify" }, Merchants = new List() }; _mockWechatPaySettings = new Mock>(); _mockWechatPaySettings.Setup(x => x.Value).Returns(wechatPaySettings); _mockRedisService = new Mock(); } private MiAssessmentDbContext CreateInMemoryDbContext() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) .Options; return new MiAssessmentDbContext(options); } [Fact] public async Task GetOpenIdAsync_WithValidCode_ReturnsSuccessResult() { // Arrange var responseContent = @"{ ""session_key"": ""test_session_key"", ""openid"": ""test_openid_123"", ""unionid"": ""test_unionid_456"" }"; var handler = new MockHttpMessageHandler(async request => { return new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.OK, Content = new StringContent(responseContent) }; }); var httpClient = new HttpClient(handler); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetOpenIdAsync("test_code"); // Assert Assert.NotNull(result); Assert.True(result.Success); Assert.Equal("test_openid_123", result.OpenId); Assert.Equal("test_unionid_456", result.UnionId); Assert.Null(result.ErrorMessage); } [Fact] public async Task GetOpenIdAsync_WithEmptyCode_ReturnsFailureResult() { // Arrange var httpClient = new HttpClient(); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetOpenIdAsync(string.Empty); // Assert Assert.NotNull(result); Assert.False(result.Success); Assert.Null(result.OpenId); Assert.NotNull(result.ErrorMessage); } [Fact] public async Task GetOpenIdAsync_WithNullCode_ReturnsFailureResult() { // Arrange var httpClient = new HttpClient(); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetOpenIdAsync(null!); // Assert Assert.NotNull(result); Assert.False(result.Success); Assert.Null(result.OpenId); Assert.NotNull(result.ErrorMessage); } [Fact] public async Task GetOpenIdAsync_WithWechatError_ReturnsFailureResult() { // Arrange var responseContent = @"{ ""errcode"": 40001, ""errmsg"": ""invalid credential"" }"; var handler = new MockHttpMessageHandler(async request => { return new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.OK, Content = new StringContent(responseContent) }; }); var httpClient = new HttpClient(handler); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetOpenIdAsync("invalid_code"); // Assert Assert.NotNull(result); Assert.False(result.Success); Assert.Null(result.OpenId); Assert.NotNull(result.ErrorMessage); Assert.Contains("invalid credential", result.ErrorMessage); } [Fact] public async Task GetOpenIdAsync_WithHttpError_ReturnsFailureResult() { // Arrange var handler = new MockHttpMessageHandler(async request => { return new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.InternalServerError, Content = new StringContent("Server Error") }; }); var httpClient = new HttpClient(handler); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetOpenIdAsync("test_code"); // Assert Assert.NotNull(result); Assert.False(result.Success); Assert.Null(result.OpenId); Assert.NotNull(result.ErrorMessage); } [Fact] public async Task GetMobileAsync_WithValidCode_ReturnsSuccessResult() { // Arrange var responseContent = @"{ ""errcode"": 0, ""errmsg"": ""ok"", ""phone_info"": { ""phoneNumber"": ""13800138000"", ""purePhoneNumber"": ""13800138000"", ""countryCode"": ""86"" } }"; var handler = new MockHttpMessageHandler(async request => { return new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.OK, Content = new StringContent(responseContent) }; }); var httpClient = new HttpClient(handler); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetMobileAsync("test_access_token"); // Assert Assert.NotNull(result); Assert.True(result.Success); Assert.Equal("13800138000", result.Mobile); Assert.Null(result.ErrorMessage); } [Fact] public async Task GetMobileAsync_WithEmptyCode_ReturnsFailureResult() { // Arrange var httpClient = new HttpClient(); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetMobileAsync(string.Empty); // Assert Assert.NotNull(result); Assert.False(result.Success); Assert.Null(result.Mobile); Assert.NotNull(result.ErrorMessage); } [Fact] public async Task GetMobileAsync_WithWechatError_ReturnsFailureResult() { // Arrange var responseContent = @"{ ""errcode"": 40001, ""errmsg"": ""invalid access_token"" }"; var handler = new MockHttpMessageHandler(async request => { return new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.OK, Content = new StringContent(responseContent) }; }); var httpClient = new HttpClient(handler); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetMobileAsync("invalid_token"); // Assert Assert.NotNull(result); Assert.False(result.Success); Assert.Null(result.Mobile); Assert.NotNull(result.ErrorMessage); } [Fact] public async Task GetMobileAsync_WithHttpError_ReturnsFailureResult() { // Arrange var handler = new MockHttpMessageHandler(async request => { return new HttpResponseMessage { StatusCode = System.Net.HttpStatusCode.ServiceUnavailable, Content = new StringContent("Service Unavailable") }; }); var httpClient = new HttpClient(handler); var dbContext = CreateInMemoryDbContext(); var wechatService = new WechatService(httpClient, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext); // Act var result = await wechatService.GetMobileAsync("test_token"); // Assert Assert.NotNull(result); Assert.False(result.Success); Assert.Null(result.Mobile); Assert.NotNull(result.ErrorMessage); } [Fact] public void WechatService_WithNullHttpClient_ThrowsArgumentNullException() { // Arrange var dbContext = CreateInMemoryDbContext(); // Act & Assert Assert.Throws(() => new WechatService(null!, _mockLogger.Object, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext)); } [Fact] public void WechatService_WithNullLogger_ThrowsArgumentNullException() { // Arrange var httpClient = new HttpClient(); var dbContext = CreateInMemoryDbContext(); // Act & Assert Assert.Throws(() => new WechatService(httpClient, null!, _wechatSettings, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext)); } [Fact] public void WechatService_WithNullWechatSettings_ThrowsArgumentNullException() { // Arrange var httpClient = new HttpClient(); var dbContext = CreateInMemoryDbContext(); // Act & Assert Assert.Throws(() => new WechatService(httpClient, _mockLogger.Object, null!, _mockWechatPaySettings.Object, _mockRedisService.Object, dbContext)); } }