578 lines
17 KiB
C#
578 lines
17 KiB
C#
using HoneyBox.Admin.Business.Models;
|
|
using HoneyBox.Admin.Business.Models.Reward;
|
|
using HoneyBox.Admin.Business.Models.SignConfig;
|
|
using HoneyBox.Admin.Business.Services;
|
|
using HoneyBox.Model.Data;
|
|
using HoneyBox.Model.Entities;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace HoneyBox.Tests.Services;
|
|
|
|
/// <summary>
|
|
/// SignConfigService 单元测试
|
|
/// </summary>
|
|
public class SignConfigServiceTests : IDisposable
|
|
{
|
|
private readonly HoneyBoxDbContext _dbContext;
|
|
private readonly Mock<ILogger<SignConfigService>> _mockLogger;
|
|
private readonly SignConfigService _signConfigService;
|
|
|
|
public SignConfigServiceTests()
|
|
{
|
|
// 使用 InMemory 数据库
|
|
var options = new DbContextOptionsBuilder<HoneyBoxDbContext>()
|
|
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
|
.Options;
|
|
|
|
_dbContext = new HoneyBoxDbContext(options);
|
|
_mockLogger = new Mock<ILogger<SignConfigService>>();
|
|
|
|
_signConfigService = new SignConfigService(_dbContext, _mockLogger.Object);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_dbContext.Dispose();
|
|
}
|
|
|
|
#region GetSignConfigsAsync Tests
|
|
|
|
[Fact]
|
|
public async Task GetSignConfigsAsync_WithDailyType_ReturnsDailyConfigs()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
var request = new SignConfigListRequest { Page = 1, PageSize = 10, Type = 1 };
|
|
|
|
// Act
|
|
var result = await _signConfigService.GetSignConfigsAsync(request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Equal(2, result.Total);
|
|
Assert.All(result.List, s => Assert.Equal(1, s.Type));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetSignConfigsAsync_WithCumulativeType_ReturnsCumulativeConfigs()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
var request = new SignConfigListRequest { Page = 1, PageSize = 10, Type = 2 };
|
|
|
|
// Act
|
|
var result = await _signConfigService.GetSignConfigsAsync(request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Equal(1, result.Total);
|
|
Assert.All(result.List, s => Assert.Equal(2, s.Type));
|
|
}
|
|
|
|
|
|
[Fact]
|
|
public async Task GetSignConfigsAsync_WithKeywordFilter_ReturnsFilteredConfigs()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
var request = new SignConfigListRequest { Page = 1, PageSize = 10, Type = 1, Keyword = "第1天" };
|
|
|
|
// Act
|
|
var result = await _signConfigService.GetSignConfigsAsync(request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Equal(1, result.Total);
|
|
Assert.Contains("第1天", result.List[0].Title);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetSignConfigsAsync_WithPagination_ReturnsCorrectPage()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
var request = new SignConfigListRequest { Page = 1, PageSize = 1, Type = 1 };
|
|
|
|
// Act
|
|
var result = await _signConfigService.GetSignConfigsAsync(request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Equal(2, result.Total);
|
|
Assert.Single(result.List);
|
|
Assert.Equal(1, result.Page);
|
|
Assert.Equal(1, result.PageSize);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetSignConfigsAsync_WithRewards_ReturnsConfigsWithRewards()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigsWithRewards();
|
|
var request = new SignConfigListRequest { Page = 1, PageSize = 10, Type = 1 };
|
|
|
|
// Act
|
|
var result = await _signConfigService.GetSignConfigsAsync(request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.True(result.List.Count > 0);
|
|
Assert.True(result.List[0].Rewards.Count > 0);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSignConfigByIdAsync Tests
|
|
|
|
[Fact]
|
|
public async Task GetSignConfigByIdAsync_WithExistingId_ReturnsConfig()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
|
|
// Act
|
|
var result = await _signConfigService.GetSignConfigByIdAsync(1);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Equal(1, result.Id);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetSignConfigByIdAsync_WithNonExistingId_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
|
|
// Act
|
|
var result = await _signConfigService.GetSignConfigByIdAsync(999);
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CreateSignConfigAsync Tests
|
|
|
|
[Fact]
|
|
public async Task CreateSignConfigAsync_WithValidRequest_CreatesConfig()
|
|
{
|
|
// Arrange
|
|
var request = new SignConfigCreateRequest
|
|
{
|
|
Type = 1,
|
|
Day = 1,
|
|
Title = "测试签到配置",
|
|
Icon = "https://example.com/icon.png",
|
|
Sort = 1,
|
|
Description = "测试描述",
|
|
Rewards = new List<RewardItem>
|
|
{
|
|
new() { RewardType = 1, RewardValue = 100, Description = "钻石奖励" }
|
|
}
|
|
};
|
|
|
|
// Act
|
|
var id = await _signConfigService.CreateSignConfigAsync(request);
|
|
|
|
// Assert
|
|
Assert.True(id > 0);
|
|
var config = await _dbContext.SignConfigs.FindAsync(id);
|
|
Assert.NotNull(config);
|
|
Assert.Equal((byte)1, config.Type);
|
|
Assert.Equal((byte)1, config.Day);
|
|
Assert.Equal("测试签到配置", config.Title);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateSignConfigAsync_WithInvalidType_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var request = new SignConfigCreateRequest
|
|
{
|
|
Type = 3,
|
|
Day = 1,
|
|
Title = "测试签到配置"
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.CreateSignConfigAsync(request));
|
|
Assert.Equal(BusinessErrorCodes.ValidationFailed, ex.Code);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateSignConfigAsync_WithEmptyTitle_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var request = new SignConfigCreateRequest
|
|
{
|
|
Type = 1,
|
|
Day = 1,
|
|
Title = ""
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.CreateSignConfigAsync(request));
|
|
Assert.Equal(BusinessErrorCodes.ValidationFailed, ex.Code);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateSignConfigAsync_WithZeroDay_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var request = new SignConfigCreateRequest
|
|
{
|
|
Type = 1,
|
|
Day = 0,
|
|
Title = "测试签到配置"
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.CreateSignConfigAsync(request));
|
|
Assert.Equal(BusinessErrorCodes.ValidationFailed, ex.Code);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateSignConfigAsync Tests
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigAsync_WithExistingConfig_UpdatesConfig()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
var request = new SignConfigUpdateRequest
|
|
{
|
|
Type = 1,
|
|
Day = 2,
|
|
Title = "更新后的标题",
|
|
Icon = "https://example.com/new-icon.png",
|
|
Sort = 10,
|
|
Description = "更新后的描述"
|
|
};
|
|
|
|
// Act
|
|
var result = await _signConfigService.UpdateSignConfigAsync(1, request);
|
|
|
|
// Assert
|
|
Assert.True(result);
|
|
var config = await _dbContext.SignConfigs.FindAsync(1);
|
|
Assert.NotNull(config);
|
|
Assert.Equal((byte)2, config.Day);
|
|
Assert.Equal("更新后的标题", config.Title);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigAsync_WithNonExistingConfig_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var request = new SignConfigUpdateRequest
|
|
{
|
|
Type = 1,
|
|
Day = 1,
|
|
Title = "测试"
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.UpdateSignConfigAsync(999, request));
|
|
Assert.Equal(BusinessErrorCodes.NotFound, ex.Code);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DeleteSignConfigAsync Tests
|
|
|
|
[Fact]
|
|
public async Task DeleteSignConfigAsync_WithExistingConfig_DeletesConfig()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
|
|
// Act
|
|
var result = await _signConfigService.DeleteSignConfigAsync(1);
|
|
|
|
// Assert
|
|
Assert.True(result);
|
|
var config = await _dbContext.SignConfigs.FindAsync(1);
|
|
Assert.Null(config);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteSignConfigAsync_WithNonExistingConfig_ThrowsException()
|
|
{
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.DeleteSignConfigAsync(999));
|
|
Assert.Equal(BusinessErrorCodes.NotFound, ex.Code);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteSignConfigAsync_WithRewards_DeletesConfigAndRewards()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigsWithRewards();
|
|
var configBefore = await _dbContext.SignConfigs.FindAsync(1);
|
|
var rewardsBefore = await _dbContext.Rewards.Where(r => r.RewardId == configBefore!.RewardId).ToListAsync();
|
|
Assert.NotEmpty(rewardsBefore);
|
|
|
|
// Act
|
|
var result = await _signConfigService.DeleteSignConfigAsync(1);
|
|
|
|
// Assert
|
|
Assert.True(result);
|
|
var config = await _dbContext.SignConfigs.FindAsync(1);
|
|
Assert.Null(config);
|
|
var rewardsAfter = await _dbContext.Rewards.Where(r => r.RewardId == configBefore!.RewardId).ToListAsync();
|
|
Assert.Empty(rewardsAfter);
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region UpdateSignConfigStatusAsync Tests
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigStatusAsync_WithValidStatus_UpdatesStatus()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
|
|
// Act
|
|
var result = await _signConfigService.UpdateSignConfigStatusAsync(1, 0);
|
|
|
|
// Assert
|
|
Assert.True(result);
|
|
var config = await _dbContext.SignConfigs.FindAsync(1);
|
|
Assert.NotNull(config);
|
|
Assert.Equal(0, config.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigStatusAsync_WithInvalidStatus_ThrowsException()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.UpdateSignConfigStatusAsync(1, 2));
|
|
Assert.Equal(BusinessErrorCodes.ValidationFailed, ex.Code);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigStatusAsync_WithNonExistingConfig_ThrowsException()
|
|
{
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.UpdateSignConfigStatusAsync(999, 1));
|
|
Assert.Equal(BusinessErrorCodes.NotFound, ex.Code);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateSignConfigSortAsync Tests
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigSortAsync_WithValidSort_UpdatesSort()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigs();
|
|
|
|
// Act
|
|
var result = await _signConfigService.UpdateSignConfigSortAsync(1, 100);
|
|
|
|
// Assert
|
|
Assert.True(result);
|
|
var config = await _dbContext.SignConfigs.FindAsync(1);
|
|
Assert.NotNull(config);
|
|
Assert.Equal(100, config.Sort);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigSortAsync_WithNonExistingConfig_ThrowsException()
|
|
{
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.UpdateSignConfigSortAsync(999, 1));
|
|
Assert.Equal(BusinessErrorCodes.NotFound, ex.Code);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateSignConfigRewardAsync Tests
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigRewardAsync_WithValidRequest_UpdatesRewards()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigsWithRewards();
|
|
var request = new SignConfigRewardRequest
|
|
{
|
|
Rewards = new List<RewardItem>
|
|
{
|
|
new() { RewardType = 1, RewardValue = 200, Description = "新钻石奖励" },
|
|
new() { RewardType = 2, RewardValue = 100, Description = "新UU币奖励" }
|
|
}
|
|
};
|
|
|
|
// Act
|
|
var result = await _signConfigService.UpdateSignConfigRewardAsync(1, request);
|
|
|
|
// Assert
|
|
Assert.True(result);
|
|
var config = await _dbContext.SignConfigs.FindAsync(1);
|
|
var rewards = await _dbContext.Rewards.Where(r => r.RewardId == config!.RewardId).ToListAsync();
|
|
Assert.Equal(2, rewards.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigRewardAsync_WithEmptyRewards_DeletesExistingRewards()
|
|
{
|
|
// Arrange
|
|
await SeedTestSignConfigsWithRewards();
|
|
var request = new SignConfigRewardRequest
|
|
{
|
|
Rewards = new List<RewardItem>()
|
|
};
|
|
|
|
// Act
|
|
var result = await _signConfigService.UpdateSignConfigRewardAsync(1, request);
|
|
|
|
// Assert
|
|
Assert.True(result);
|
|
var config = await _dbContext.SignConfigs.FindAsync(1);
|
|
var rewards = await _dbContext.Rewards.Where(r => r.RewardId == config!.RewardId).ToListAsync();
|
|
Assert.Empty(rewards);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateSignConfigRewardAsync_WithNonExistingConfig_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var request = new SignConfigRewardRequest
|
|
{
|
|
Rewards = new List<RewardItem>()
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<BusinessException>(
|
|
() => _signConfigService.UpdateSignConfigRewardAsync(999, request));
|
|
Assert.Equal(BusinessErrorCodes.NotFound, ex.Code);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helper Methods
|
|
|
|
private async Task SeedTestSignConfigs()
|
|
{
|
|
var configs = new List<SignConfig>
|
|
{
|
|
new()
|
|
{
|
|
Id = 1,
|
|
Type = 1,
|
|
Day = 1,
|
|
Title = "第1天签到",
|
|
Icon = "https://example.com/icon1.png",
|
|
Status = 1,
|
|
Sort = 1,
|
|
RewardId = "sign_001",
|
|
Description = "第1天签到奖励",
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
},
|
|
new()
|
|
{
|
|
Id = 2,
|
|
Type = 1,
|
|
Day = 2,
|
|
Title = "第2天签到",
|
|
Icon = "https://example.com/icon2.png",
|
|
Status = 1,
|
|
Sort = 2,
|
|
RewardId = "sign_002",
|
|
Description = "第2天签到奖励",
|
|
CreatedAt = DateTime.Now.AddMinutes(-1),
|
|
UpdatedAt = DateTime.Now.AddMinutes(-1)
|
|
},
|
|
new()
|
|
{
|
|
Id = 3,
|
|
Type = 2,
|
|
Day = 7,
|
|
Title = "累计7天签到",
|
|
Icon = "https://example.com/icon3.png",
|
|
Status = 1,
|
|
Sort = 1,
|
|
RewardId = "sign_003",
|
|
Description = "累计7天签到奖励",
|
|
CreatedAt = DateTime.Now.AddMinutes(-2),
|
|
UpdatedAt = DateTime.Now.AddMinutes(-2)
|
|
}
|
|
};
|
|
|
|
_dbContext.SignConfigs.AddRange(configs);
|
|
await _dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
private async Task SeedTestSignConfigsWithRewards()
|
|
{
|
|
var configs = new List<SignConfig>
|
|
{
|
|
new()
|
|
{
|
|
Id = 1,
|
|
Type = 1,
|
|
Day = 1,
|
|
Title = "第1天签到",
|
|
Icon = "https://example.com/icon1.png",
|
|
Status = 1,
|
|
Sort = 1,
|
|
RewardId = "sign_reward_001",
|
|
Description = "第1天签到奖励",
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
}
|
|
};
|
|
|
|
var rewards = new List<Reward>
|
|
{
|
|
new()
|
|
{
|
|
Id = 100,
|
|
RewardId = "sign_reward_001",
|
|
RewardType = 1,
|
|
RewardValue = 100,
|
|
Description = "钻石奖励",
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
},
|
|
new()
|
|
{
|
|
Id = 101,
|
|
RewardId = "sign_reward_001",
|
|
RewardType = 2,
|
|
RewardValue = 50,
|
|
Description = "UU币奖励",
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
}
|
|
};
|
|
|
|
_dbContext.SignConfigs.AddRange(configs);
|
|
_dbContext.Rewards.AddRange(rewards);
|
|
await _dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
#endregion
|
|
}
|