587 lines
19 KiB
C#
587 lines
19 KiB
C#
using HoneyBox.Core.Interfaces;
|
|
using HoneyBox.Core.Services;
|
|
using HoneyBox.Model.Data;
|
|
using HoneyBox.Model.Entities;
|
|
using HoneyBox.Model.Models.Order;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
using Microsoft.Extensions.Logging;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace HoneyBox.Tests.Integration;
|
|
|
|
/// <summary>
|
|
/// 仓库服务集成测试
|
|
/// 测试奖品回收和发货流程
|
|
/// Requirements: 10.1-17.3
|
|
/// </summary>
|
|
public class WarehouseServiceIntegrationTests
|
|
{
|
|
private HoneyBoxDbContext CreateInMemoryDbContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<HoneyBoxDbContext>()
|
|
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
|
|
.ConfigureWarnings(w => w.Ignore(InMemoryEventId.TransactionIgnoredWarning))
|
|
.Options;
|
|
|
|
return new HoneyBoxDbContext(options);
|
|
}
|
|
|
|
private WarehouseService CreateWarehouseService(HoneyBoxDbContext dbContext)
|
|
{
|
|
var mockLogger = new Mock<ILogger<WarehouseService>>();
|
|
var mockLogisticsService = new Mock<ILogisticsService>();
|
|
var mockWechatService = new Mock<IWechatService>();
|
|
return new WarehouseService(dbContext, mockLogger.Object, mockLogisticsService.Object, mockWechatService.Object);
|
|
}
|
|
|
|
#region 测试数据准备
|
|
|
|
private async Task<User> CreateTestUserAsync(HoneyBoxDbContext dbContext, decimal money2 = 0)
|
|
{
|
|
var user = new User
|
|
{
|
|
Id = 1,
|
|
OpenId = "test_openid",
|
|
Uid = "test_uid",
|
|
Nickname = "测试用户",
|
|
HeadImg = "avatar.jpg",
|
|
Mobile = "13800138000",
|
|
Money = 100,
|
|
Integral = 1000,
|
|
Money2 = money2,
|
|
Status = 1,
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
};
|
|
await dbContext.Users.AddAsync(user);
|
|
await dbContext.SaveChangesAsync();
|
|
return user;
|
|
}
|
|
|
|
private async Task<Good> CreateTestGoodsAsync(HoneyBoxDbContext dbContext)
|
|
{
|
|
var goods = new Good
|
|
{
|
|
Id = 1,
|
|
Title = "测试商品",
|
|
Type = 1,
|
|
Status = 1,
|
|
Price = 10,
|
|
Stock = 10,
|
|
ImgUrl = "img.jpg",
|
|
ImgUrlDetail = "detail.jpg"
|
|
};
|
|
await dbContext.Goods.AddAsync(goods);
|
|
await dbContext.SaveChangesAsync();
|
|
return goods;
|
|
}
|
|
|
|
private async Task<List<OrderItem>> CreateTestOrderItemsAsync(HoneyBoxDbContext dbContext, int userId, int count = 3)
|
|
{
|
|
var items = new List<OrderItem>();
|
|
for (int i = 1; i <= count; i++)
|
|
{
|
|
items.Add(new OrderItem
|
|
{
|
|
Id = i,
|
|
OrderId = 1,
|
|
UserId = userId,
|
|
GoodsId = 1,
|
|
ShangId = 10,
|
|
GoodslistId = i,
|
|
GoodslistTitle = $"奖品{i}",
|
|
GoodslistImgurl = $"prize{i}.jpg",
|
|
GoodslistPrice = 100,
|
|
GoodslistMoney = 50, // 回收金额50
|
|
GoodslistType = 1, // 现货
|
|
Status = 0, // 待处理
|
|
InsuranceIs = 0,
|
|
OrderType = 1,
|
|
PrizeCode = $"PRIZE_{i}",
|
|
Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
});
|
|
}
|
|
await dbContext.OrderItems.AddRangeAsync(items);
|
|
await dbContext.SaveChangesAsync();
|
|
return items;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 仓库首页查询测试 (Requirements 10.1-10.3)
|
|
|
|
/// <summary>
|
|
/// 测试仓库首页查询 - 赏品类型
|
|
/// Requirements: 10.1, 10.2
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task GetWarehouseIndex_PrizesType_ReturnsCorrectItems()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
await CreateTestGoodsAsync(dbContext);
|
|
await CreateTestOrderItemsAsync(dbContext, 1, 5);
|
|
|
|
var request = new WarehouseIndexRequest
|
|
{
|
|
Type = 1, // 赏品
|
|
Page = 1
|
|
};
|
|
|
|
// Act
|
|
var result = await service.GetWarehouseIndexAsync(1, request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.True(result.Total > 0);
|
|
Assert.NotEmpty(result.Data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试仓库首页查询 - 状态筛选
|
|
/// Requirements: 10.2
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task GetWarehouseIndex_FiltersByStatus_ReturnsFilteredItems()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
await CreateTestGoodsAsync(dbContext);
|
|
|
|
// 创建不同状态的奖品
|
|
var items = new List<OrderItem>
|
|
{
|
|
new() { Id = 1, OrderId = 1, UserId = 1, GoodsId = 1, ShangId = 10, GoodslistTitle = "待处理奖品", GoodslistMoney = 50, GoodslistType = 1, Status = 0, InsuranceIs = 0, OrderType = 1, PrizeCode = "P1", Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
|
|
new() { Id = 2, OrderId = 1, UserId = 1, GoodsId = 1, ShangId = 10, GoodslistTitle = "已回收奖品", GoodslistMoney = 50, GoodslistType = 1, Status = 1, InsuranceIs = 0, OrderType = 1, PrizeCode = "P2", Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
|
|
new() { Id = 3, OrderId = 1, UserId = 1, GoodsId = 1, ShangId = 10, GoodslistTitle = "已发货奖品", GoodslistMoney = 50, GoodslistType = 1, Status = 2, InsuranceIs = 0, OrderType = 1, PrizeCode = "P3", Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
|
|
};
|
|
await dbContext.OrderItems.AddRangeAsync(items);
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
var request = new WarehouseIndexRequest
|
|
{
|
|
Type = 1,
|
|
Page = 1
|
|
};
|
|
|
|
// Act
|
|
var result = await service.GetWarehouseIndexAsync(1, request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
// 只返回status=0的待处理奖品
|
|
Assert.Equal(1, result.Total);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试仓库首页查询 - 无限赏类型
|
|
/// Requirements: 10.3
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task GetWarehouseIndex_InfiniteType_ReturnsInfiniteItems()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
await CreateTestGoodsAsync(dbContext);
|
|
|
|
// 创建无限赏奖品
|
|
var items = new List<OrderItem>
|
|
{
|
|
new() { Id = 1, OrderId = 1, UserId = 1, GoodsId = 1, ShangId = 34, GoodslistTitle = "无限赏奖品", GoodslistMoney = 50, GoodslistType = 1, Status = 0, InsuranceIs = 0, OrderType = 2, PrizeCode = "INF1", Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
|
|
};
|
|
await dbContext.OrderItems.AddRangeAsync(items);
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
var request = new WarehouseIndexRequest
|
|
{
|
|
Type = 5, // 无限赏
|
|
Page = 1
|
|
};
|
|
|
|
// Act
|
|
var result = await service.GetWarehouseIndexAsync(1, request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Equal(1, result.Total);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 奖品回收测试 (Requirements 11.1-11.5)
|
|
|
|
/// <summary>
|
|
/// 测试奖品回收 - 成功回收
|
|
/// Requirements: 11.1, 11.2, 11.3, 11.4
|
|
/// Note: This test requires a real database due to transaction and ExecuteUpdate usage
|
|
/// </summary>
|
|
[Fact(Skip = "InMemory database does not support transactions and ExecuteUpdate")]
|
|
public async Task RecoveryPrizes_Success_UpdatesStatusAndBalance()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext, money2: 0);
|
|
await CreateTestGoodsAsync(dbContext);
|
|
await CreateTestOrderItemsAsync(dbContext, 1, 2);
|
|
|
|
// 构建回收信息
|
|
var recoveryInfo = System.Text.Json.JsonSerializer.Serialize(new[]
|
|
{
|
|
new { prize_code = "PRIZE_1", number = 1 },
|
|
new { prize_code = "PRIZE_2", number = 1 }
|
|
});
|
|
|
|
var request = new RecoveryRequest
|
|
{
|
|
RecoveryInfo = recoveryInfo
|
|
};
|
|
|
|
// Act
|
|
var result = await service.RecoveryPrizesAsync(1, request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Equal(2, result.Count);
|
|
Assert.NotEmpty(result.RecoveryNum);
|
|
|
|
// 验证奖品状态已更新
|
|
var items = await dbContext.OrderItems.Where(o => o.UserId == 1).ToListAsync();
|
|
Assert.All(items, item => Assert.Equal(1, item.Status)); // 已回收
|
|
|
|
// 验证用户余额已增加 (50 * 2 * 100 = 10000 哈尼券)
|
|
var user = await dbContext.Users.FindAsync(1);
|
|
Assert.NotNull(user);
|
|
Assert.Equal(10000, user.Money2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试奖品回收 - 空回收信息
|
|
/// Requirements: 11.5
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task RecoveryPrizes_EmptyInfo_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
|
|
var request = new RecoveryRequest
|
|
{
|
|
RecoveryInfo = ""
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
|
() => service.RecoveryPrizesAsync(1, request));
|
|
Assert.Contains("选择", ex.Message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试奖品回收 - 无效的回收信息格式
|
|
/// Requirements: 11.5
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task RecoveryPrizes_InvalidFormat_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
|
|
var request = new RecoveryRequest
|
|
{
|
|
RecoveryInfo = "invalid json"
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
|
() => service.RecoveryPrizesAsync(1, request));
|
|
Assert.Contains("格式错误", ex.Message);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 奖品发货测试 (Requirements 12.1-12.5, 13.1-13.2)
|
|
|
|
/// <summary>
|
|
/// 测试奖品发货申请 - 成功
|
|
/// Requirements: 12.1, 12.2, 12.3, 12.4
|
|
/// Note: This test requires a real database due to transaction usage
|
|
/// </summary>
|
|
[Fact(Skip = "InMemory database does not support transactions")]
|
|
public async Task SendPrizes_Success_CreatesDeliveryRecord()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
await CreateTestGoodsAsync(dbContext);
|
|
await CreateTestOrderItemsAsync(dbContext, 1, 2);
|
|
|
|
// 构建发货信息JSON
|
|
var recoveryInfo = System.Text.Json.JsonSerializer.Serialize(new[]
|
|
{
|
|
new { prize_code = "PRIZE_1", number = 1 },
|
|
new { prize_code = "PRIZE_2", number = 1 }
|
|
});
|
|
|
|
var request = new SendRequest
|
|
{
|
|
Type = 1,
|
|
RecoveryInfo = recoveryInfo,
|
|
Name = "张三",
|
|
Mobile = "13800138000",
|
|
Address = "北京市朝阳区xxx街道xxx号"
|
|
};
|
|
|
|
// Act
|
|
var result = await service.SendPrizesAsync(1, request);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.NotEmpty(result.OrderNo);
|
|
|
|
// 验证发货记录已创建
|
|
var delivery = await dbContext.OrderItemsSends.FirstOrDefaultAsync();
|
|
Assert.NotNull(delivery);
|
|
Assert.Equal("张三", delivery.Name);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试奖品发货申请 - 地址信息不完整
|
|
/// Requirements: 12.5
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task SendPrizes_IncompleteAddress_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
await CreateTestGoodsAsync(dbContext);
|
|
await CreateTestOrderItemsAsync(dbContext, 1);
|
|
|
|
var recoveryInfo = System.Text.Json.JsonSerializer.Serialize(new[]
|
|
{
|
|
new { prize_code = "PRIZE_1", number = 1 }
|
|
});
|
|
|
|
var request = new SendRequest
|
|
{
|
|
Type = 1,
|
|
RecoveryInfo = recoveryInfo,
|
|
Name = "", // 空姓名
|
|
Mobile = "13800138000",
|
|
Address = "北京市"
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
|
() => service.SendPrizesAsync(1, request));
|
|
Assert.Contains("收货", ex.Message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试奖品发货申请 - 空订单列表
|
|
/// Requirements: 12.5
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task SendPrizes_EmptyOrderList_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
|
|
var request = new SendRequest
|
|
{
|
|
Type = 1,
|
|
RecoveryInfo = "",
|
|
Name = "张三",
|
|
Mobile = "13800138000",
|
|
Address = "北京市"
|
|
};
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
|
() => service.SendPrizesAsync(1, request));
|
|
Assert.Contains("选择", ex.Message);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 发货记录查询测试 (Requirements 14.1-14.3, 15.1-15.3)
|
|
|
|
/// <summary>
|
|
/// 测试发货记录查询 - 分页
|
|
/// Requirements: 14.1, 14.3
|
|
/// Note: This test requires a real database due to ExecuteUpdate usage in the service
|
|
/// </summary>
|
|
[Fact(Skip = "InMemory database does not support ExecuteUpdate")]
|
|
public async Task GetSendRecords_Pagination_ReturnsCorrectPage()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
|
|
// 创建15条发货记录
|
|
var records = Enumerable.Range(1, 15).Select(i => new OrderItemsSend
|
|
{
|
|
Id = i,
|
|
UserId = 1,
|
|
SendNum = $"SEND_{i:0000}",
|
|
Name = $"收货人{i}",
|
|
Mobile = "138****8000",
|
|
Address = $"地址{i}",
|
|
Status = 1, // 待发货
|
|
Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() - i * 60,
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
}).ToList();
|
|
await dbContext.OrderItemsSends.AddRangeAsync(records);
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
// Act
|
|
var page1 = await service.GetSendRecordsAsync(1, 1, 1);
|
|
var page2 = await service.GetSendRecordsAsync(1, 2, 1);
|
|
|
|
// Assert
|
|
Assert.Equal(15, page1.Total);
|
|
Assert.Equal(10, page1.Data.Count);
|
|
Assert.Equal(5, page2.Data.Count);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试发货记录详情查询
|
|
/// Requirements: 15.1, 15.2
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task GetSendRecordDetail_ReturnsCompleteInfo()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
|
|
// 创建发货记录
|
|
var sendRecord = new OrderItemsSend
|
|
{
|
|
Id = 1,
|
|
UserId = 1,
|
|
SendNum = "SEND_0001",
|
|
Name = "张三",
|
|
Mobile = "13800138000",
|
|
Address = "北京市朝阳区",
|
|
Status = 1, // 待发货
|
|
Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
};
|
|
await dbContext.OrderItemsSends.AddAsync(sendRecord);
|
|
|
|
// 创建关联的奖品
|
|
var items = new List<OrderItem>
|
|
{
|
|
new() { Id = 1, OrderId = 1, UserId = 1, GoodsId = 1, ShangId = 10, SendNum = "SEND_0001", GoodslistTitle = "奖品1", GoodslistMoney = 50, Status = 2, Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
|
|
};
|
|
await dbContext.OrderItems.AddRangeAsync(items);
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
// Act
|
|
var result = await service.GetSendRecordDetailAsync(1, 1);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.Equal("SEND_0001", result.SendNum);
|
|
Assert.Equal("张三", result.Name);
|
|
Assert.NotNull(result.Goods);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 测试发货记录详情查询 - 记录不存在
|
|
/// Requirements: 15.3
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task GetSendRecordDetail_NotFound_ThrowsException()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
|
|
// Act & Assert
|
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
|
() => service.GetSendRecordDetailAsync(1, 999));
|
|
Assert.Contains("参数错误", ex.Message);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 回收记录查询测试 (Requirements 16.1-16.2)
|
|
|
|
/// <summary>
|
|
/// 测试回收记录查询 - 分页
|
|
/// Requirements: 16.1, 16.2
|
|
/// </summary>
|
|
[Fact]
|
|
public async Task GetRecoveryRecords_Pagination_ReturnsCorrectPage()
|
|
{
|
|
// Arrange
|
|
var dbContext = CreateInMemoryDbContext();
|
|
var service = CreateWarehouseService(dbContext);
|
|
|
|
await CreateTestUserAsync(dbContext);
|
|
|
|
// 创建10条回收记录
|
|
var records = Enumerable.Range(1, 10).Select(i => new OrderItemsRecovery
|
|
{
|
|
Id = i,
|
|
UserId = 1,
|
|
RecoveryNum = $"REC_{i:0000}",
|
|
Money = 50 * i,
|
|
Count = i,
|
|
Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() - i * 60,
|
|
CreatedAt = DateTime.Now,
|
|
UpdatedAt = DateTime.Now
|
|
}).ToList();
|
|
await dbContext.OrderItemsRecoveries.AddRangeAsync(records);
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
// Act
|
|
var result = await service.GetRecoveryRecordsAsync(1, 1);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
Assert.NotNull(result.Data);
|
|
Assert.True(result.Data.Count <= 10);
|
|
Assert.True(result.LastPage >= 1);
|
|
}
|
|
|
|
#endregion
|
|
}
|