using System.Text.Json; using System.Text.Json.Serialization; using HoneyBox.Model.Base; using HoneyBox.Model.Models; using HoneyBox.Model.Models.Order; using HoneyBox.Model.Models.Goods; using HoneyBox.Model.Models.Payment; using HoneyBox.Model.Models.Lottery; using Xunit; namespace HoneyBox.Tests.Integration; /// /// API响应格式验证测试 /// 验证所有接口响应格式与PHP API一致 /// Requirements: 18.1-18.4 /// public class ApiResponseFormatTests { private readonly JsonSerializerOptions _jsonOptions; public ApiResponseFormatTests() { _jsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = null, // Use JsonPropertyName attributes WriteIndented = false }; } #region ApiResponse Base Format Tests /// /// 验证ApiResponse基类使用正确的snake_case字段名 /// Requirements: 18.1, 18.3 /// [Fact] public void ApiResponse_ShouldUseCorrectFieldNames() { // Arrange var response = ApiResponse.Success("success"); // Act var json = JsonSerializer.Serialize(response, _jsonOptions); // Assert Assert.Contains("\"status\":", json); Assert.Contains("\"msg\":", json); Assert.DoesNotContain("\"Status\":", json); Assert.DoesNotContain("\"Msg\":", json); } /// /// 验证ApiResponse包含data字段 /// Requirements: 18.1, 18.3 /// [Fact] public void ApiResponseGeneric_ShouldIncludeDataField() { // Arrange var response = ApiResponse.Success("test data"); // Act var json = JsonSerializer.Serialize(response, _jsonOptions); // Assert Assert.Contains("\"status\":", json); Assert.Contains("\"msg\":", json); Assert.Contains("\"data\":", json); Assert.DoesNotContain("\"Data\":", json); } /// /// 验证成功响应status=1 /// Requirements: 18.1 /// [Fact] public void ApiResponse_Success_ShouldHaveStatus1() { // Arrange & Act var response = ApiResponse.Success(); // Assert Assert.Equal(1, response.Status); } /// /// 验证失败响应status=0 /// Requirements: 18.1 /// [Fact] public void ApiResponse_Fail_ShouldHaveStatus0() { // Arrange & Act var response = ApiResponse.Fail("error"); // Assert Assert.Equal(0, response.Status); } /// /// 验证未授权响应status=-1 /// Requirements: 18.1 /// [Fact] public void ApiResponse_Unauthorized_ShouldHaveStatusMinus1() { // Arrange & Act var response = ApiResponse.Unauthorized(); // Assert Assert.Equal(-1, response.Status); } #endregion #region Order Models Format Tests /// /// 验证OrderMoneyRequest使用snake_case /// Requirements: 18.2 /// [Fact] public void OrderMoneyRequest_ShouldUseSnakeCase() { // Arrange var request = new OrderMoneyRequest { GoodsId = 1, Num = 1, PrizeNum = 1, UseMoneyIs = 1, UseIntegralIs = 1, UseMoney2Is = 1 }; // Act var json = JsonSerializer.Serialize(request, _jsonOptions); // Assert Assert.Contains("\"goods_id\":", json); Assert.Contains("\"num\":", json); Assert.Contains("\"prize_num\":", json); Assert.Contains("\"use_money_is\":", json); Assert.Contains("\"use_integral_is\":", json); Assert.Contains("\"use_money2_is\":", json); } /// /// 验证OrderCalculationDto使用snake_case /// Requirements: 18.2 /// [Fact] public void OrderCalculationDto_ShouldUseSnakeCase() { // Arrange var dto = new OrderCalculationDto { OrderTotal = "100.00", Price = "10.00", UserMoney = "50.00", UserIntegral = "100.00", UserMoney2 = "20.00", UseMoney = "10.00", UseIntegral = "5.00", UseMoney2 = "3.00", UseCoupon = "2.00" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"order_total\":", json); Assert.Contains("\"price\":", json); Assert.Contains("\"user_money\":", json); Assert.Contains("\"user_integral\":", json); Assert.Contains("\"user_money2\":", json); Assert.Contains("\"use_money\":", json); Assert.Contains("\"use_integral\":", json); Assert.Contains("\"use_coupon\":", json); } /// /// 验证OrderBuyResponseDto使用snake_case /// Requirements: 18.2 /// [Fact] public void OrderBuyResponseDto_ShouldUseSnakeCase() { // Arrange var dto = new OrderBuyResponseDto { Status = 1, OrderNum = "TEST001" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"status\":", json); Assert.Contains("\"order_num\":", json); Assert.Contains("\"res\":", json); } /// /// 验证OrderListDto使用snake_case /// Requirements: 18.2 /// [Fact] public void OrderListDto_ShouldUseSnakeCase() { // Arrange var dto = new OrderListDto { Id = 1, OrderNum = "TEST001", GoodsTitle = "Test", GoodsImgUrl = "http://test.com/img.jpg", OrderTotal = "100.00", Price = "100.00", PrizeNum = 1, Status = 1, AddTime = 1234567890, PayTime = 1234567890, OrderType = 1 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"id\":", json); Assert.Contains("\"order_num\":", json); Assert.Contains("\"goods_title\":", json); Assert.Contains("\"goods_imgurl\":", json); Assert.Contains("\"order_total\":", json); Assert.Contains("\"price\":", json); Assert.Contains("\"prize_num\":", json); Assert.Contains("\"status\":", json); Assert.Contains("\"addtime\":", json); Assert.Contains("\"pay_time\":", json); Assert.Contains("\"order_type\":", json); } /// /// 验证PrizeOrderLogDto使用snake_case /// Requirements: 18.2 /// [Fact] public void PrizeOrderLogDto_ShouldUseSnakeCase() { // Arrange var dto = new PrizeOrderLogDto { Id = 1, UserId = 1, GoodsListTitle = "Test", GoodsListImgUrl = "http://test.com/img.jpg", GoodsListPrice = "100.00", GoodsListMoney = "50.00", Status = 0, LuckNo = 1, ShangId = 1 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"id\":", json); Assert.Contains("\"user_id\":", json); Assert.Contains("\"goodslist_title\":", json); Assert.Contains("\"goodslist_imgurl\":", json); Assert.Contains("\"goodslist_price\":", json); Assert.Contains("\"goodslist_money\":", json); Assert.Contains("\"status\":", json); Assert.Contains("\"luck_no\":", json); Assert.Contains("\"shang_id\":", json); } #endregion #region Warehouse Models Format Tests /// /// 验证WarehouseIndexRequest使用snake_case /// Requirements: 18.4 /// [Fact] public void WarehouseIndexRequest_ShouldUseSnakeCase() { // Arrange var request = new WarehouseIndexRequest { Page = 1, PageSize = 10, Type = 1 }; // Act var json = JsonSerializer.Serialize(request, _jsonOptions); // Assert Assert.Contains("\"page\":", json); Assert.Contains("\"page_size\":", json); Assert.Contains("\"type\":", json); } /// /// 验证WarehouseItemDto使用snake_case /// Requirements: 18.4 /// [Fact] public void WarehouseItemDto_ShouldUseSnakeCase() { // Arrange var dto = new WarehouseItemDto { Id = 1, GoodsListTitle = "Test", GoodsListImgUrl = "http://test.com/img.jpg", GoodsListPrice = "100.00", GoodsListMoney = "50.00", Status = 0, AddTime = 1234567890, ShangId = 1, GoodsId = 1 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"id\":", json); Assert.Contains("\"goodslist_title\":", json); Assert.Contains("\"goodslist_imgurl\":", json); Assert.Contains("\"goodslist_price\":", json); Assert.Contains("\"goodslist_money\":", json); Assert.Contains("\"status\":", json); Assert.Contains("\"addtime\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"goods_id\":", json); } /// /// 验证RecoveryResultDto使用snake_case /// Requirements: 18.4 /// [Fact] public void RecoveryResultDto_ShouldUseSnakeCase() { // Arrange var dto = new RecoveryResultDto { TotalMoney = "100.00", Count = 5, RecoveryNum = "REC001", UserMoney = "150.00" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"total_money\":", json); Assert.Contains("\"count\":", json); Assert.Contains("\"recovery_num\":", json); Assert.Contains("\"user_money\":", json); } /// /// 验证SendRecordDto使用snake_case /// Requirements: 18.4 /// [Fact] public void SendRecordDto_ShouldUseSnakeCase() { // Arrange var dto = new SendRecordDto { Id = 1, SendNum = "SEND001", Name = "Test", Mobile = "138****0000", Address = "Test Address", Status = 1, StatusName = "待发货", Count = 3, Freight = "10.00", AddTime = "2024-01-01 12:00:00" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"id\":", json); Assert.Contains("\"send_num\":", json); Assert.Contains("\"name\":", json); Assert.Contains("\"mobile\":", json); Assert.Contains("\"address\":", json); Assert.Contains("\"status\":", json); Assert.Contains("\"status_name\":", json); Assert.Contains("\"count\":", json); Assert.Contains("\"freight\":", json); Assert.Contains("\"addtime\":", json); } /// /// 验证LogisticsDto使用snake_case /// Requirements: 18.4 /// [Fact] public void LogisticsDto_ShouldUseSnakeCase() { // Arrange var dto = new LogisticsDto { CourierNumber = "SF123456", CourierName = "顺丰速运", CourierCode = "SF", Count = 3, SendNum = "SEND001", DeliveryStatus = "已签收" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"courier_number\":", json); Assert.Contains("\"courier_name\":", json); Assert.Contains("\"courier_code\":", json); Assert.Contains("\"count\":", json); Assert.Contains("\"send_num\":", json); Assert.Contains("\"delivery_status\":", json); } #endregion #region PageResponse Format Tests /// /// 验证PageResponse使用snake_case /// Requirements: 18.2, 18.4 /// [Fact] public void PageResponse_ShouldUseSnakeCase() { // Arrange var response = new PageResponse { Data = new List(), LastPage = 10, Total = 100, Page = 1, PageSize = 10 }; // Act var json = JsonSerializer.Serialize(response, _jsonOptions); // Assert Assert.Contains("\"data\":", json); Assert.Contains("\"last_page\":", json); Assert.Contains("\"total\":", json); Assert.Contains("\"page\":", json); Assert.Contains("\"page_size\":", json); } #endregion #region WechatPayParams Format Tests /// /// 验证WechatPayParamsDto使用正确的字段名(微信API要求的camelCase) /// Requirements: 18.2 /// [Fact] public void WechatPayParamsDto_ShouldUseCamelCaseForWechatApi() { // Arrange var dto = new WechatPayParamsDto { AppId = "wx123456", TimeStamp = "1234567890", NonceStr = "abc123", Package = "prepay_id=xxx", SignType = "RSA", PaySign = "sign123" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert - 微信支付参数使用camelCase是正确的 Assert.Contains("\"appId\":", json); Assert.Contains("\"timeStamp\":", json); Assert.Contains("\"nonceStr\":", json); Assert.Contains("\"package\":", json); Assert.Contains("\"signType\":", json); Assert.Contains("\"paySign\":", json); } #endregion #region Complete Response Serialization Tests /// /// 验证完整的订单金额计算响应格式 /// Requirements: 18.1, 18.2 /// [Fact] public void CompleteOrderCalculationResponse_ShouldMatchPhpFormat() { // Arrange var data = new OrderCalculationDto { OrderTotal = "100.00", Price = "10.00", GoodsInfo = new GoodsInfoDto { Id = 1, Title = "Test" }, UserMoney = "50.00", UserIntegral = "100.00", UserMoney2 = "20.00" }; var response = ApiResponse.Success(data); // Act var json = JsonSerializer.Serialize(response, _jsonOptions); // Assert - 验证顶层结构 Assert.Contains("\"status\":1", json); Assert.Contains("\"msg\":\"success\"", json); Assert.Contains("\"data\":", json); // Assert - 验证数据字段 Assert.Contains("\"order_total\":\"100.00\"", json); Assert.Contains("\"price\":\"10.00\"", json); Assert.Contains("\"goods_info\":", json); Assert.Contains("\"user_money\":\"50.00\"", json); Assert.Contains("\"user_integral\":\"100.00\"", json); Assert.Contains("\"user_money2\":\"20.00\"", json); } /// /// 验证完整的仓库首页响应格式 /// Requirements: 18.3, 18.4 /// [Fact] public void CompleteWarehouseIndexResponse_ShouldMatchPhpFormat() { // Arrange var data = new WarehouseIndexResponseDto { Total = 100, Data = new List { new WarehouseGoodsGroupDto { GoodsId = 1, GoodsTitle = "Test", OrderList = new List { new WarehouseItemDto { Id = 1, GoodsListTitle = "Prize", GoodsListImgUrl = "http://test.com/img.jpg", GoodsListPrice = "100.00", GoodsListMoney = "50.00", Status = 0 } } } }, LastPage = 10 }; var response = ApiResponse.Success(data); // Act var json = JsonSerializer.Serialize(response, _jsonOptions); // Assert - 验证顶层结构 Assert.Contains("\"status\":1", json); Assert.Contains("\"msg\":\"success\"", json); Assert.Contains("\"data\":", json); // Assert - 验证数据字段 Assert.Contains("\"total\":", json); Assert.Contains("\"last_page\":", json); Assert.Contains("\"goods_id\":", json); Assert.Contains("\"goods_title\":", json); Assert.Contains("\"goodslist_title\":", json); Assert.Contains("\"goodslist_imgurl\":", json); Assert.Contains("\"goodslist_price\":", json); Assert.Contains("\"goodslist_money\":", json); } #endregion #region Payment System Response Format Tests - Requirements 10.1-10.4 /// /// 验证WechatPayResult使用正确的字段名 /// Requirements: 10.1, 10.3 /// [Fact] public void WechatPayResult_ShouldUseCorrectFieldNames() { // Arrange var result = new WechatPayResult { Status = 1, Msg = "success", Data = new WechatPayData { AppId = "wx123456", TimeStamp = "1234567890", NonceStr = "abc123", Package = "prepay_id=xxx", SignType = "MD5", PaySign = "sign123", IsWeixin = 1 } }; // Act var json = JsonSerializer.Serialize(result, _jsonOptions); // Assert - 验证顶层结构使用snake_case Assert.Contains("\"status\":", json); Assert.Contains("\"msg\":", json); Assert.Contains("\"data\":", json); Assert.DoesNotContain("\"Status\":", json); Assert.DoesNotContain("\"Msg\":", json); Assert.DoesNotContain("\"Data\":", json); } /// /// 验证WechatPayData使用正确的字段名(微信API要求的camelCase) /// Requirements: 10.2, 10.4 /// [Fact] public void WechatPayData_ShouldUseCamelCaseForWechatApi() { // Arrange var data = new WechatPayData { AppId = "wx123456", TimeStamp = "1234567890", NonceStr = "abc123", Package = "prepay_id=xxx", SignType = "MD5", PaySign = "sign123", IsWeixin = 1 }; // Act var json = JsonSerializer.Serialize(data, _jsonOptions); // Assert - 微信支付参数使用camelCase(与PHP API一致) Assert.Contains("\"appId\":", json); Assert.Contains("\"timeStamp\":", json); Assert.Contains("\"nonceStr\":", json); Assert.Contains("\"package\":", json); Assert.Contains("\"signType\":", json); Assert.Contains("\"paySign\":", json); Assert.Contains("\"is_weixin\":", json); // is_weixin使用snake_case } /// /// 验证WechatPayResult成功响应status=1 /// Requirements: 10.3 /// [Fact] public void WechatPayResult_Success_ShouldHaveStatus1() { // Arrange var result = new WechatPayResult { Status = 1, Msg = "success", Data = new WechatPayData() }; // Assert Assert.Equal(1, result.Status); } /// /// 验证WechatPayResult失败响应status=0 /// Requirements: 10.3 /// [Fact] public void WechatPayResult_Fail_ShouldHaveStatus0() { // Arrange var result = new WechatPayResult { Status = 0, Msg = "支付失败" }; // Assert Assert.Equal(0, result.Status); } /// /// 验证WechatPayRequest使用snake_case /// Requirements: 10.2 /// [Fact] public void WechatPayRequest_ShouldUseSnakeCase() { // Arrange var request = new WechatPayRequest { OrderNo = "TEST001", Amount = 100.00m, Body = "商品购买", Attach = "order_yfs", OpenId = "openid123", UserId = 1 }; // Act var json = JsonSerializer.Serialize(request, _jsonOptions); // Assert Assert.Contains("\"order_no\":", json); Assert.Contains("\"amount\":", json); Assert.Contains("\"body\":", json); Assert.Contains("\"attach\":", json); Assert.Contains("\"open_id\":", json); Assert.Contains("\"user_id\":", json); } /// /// 验证PaymentRecordDto使用snake_case /// Requirements: 10.2 /// [Fact] public void PaymentRecordDto_ShouldUseSnakeCase() { // Arrange var dto = new HoneyBox.Model.Models.Payment.PaymentRecordDto { Id = 1, UserId = 1, OrderNum = "TEST001", ChangeMoney = "100.00", Content = "支付测试", PayType = 1, PayTypeText = "微信支付", CreatedAt = 1234567890 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"id\":", json); Assert.Contains("\"user_id\":", json); Assert.Contains("\"order_num\":", json); Assert.Contains("\"change_money\":", json); Assert.Contains("\"content\":", json); Assert.Contains("\"pay_type\":", json); Assert.Contains("\"pay_type_text\":", json); Assert.Contains("\"created_at\":", json); } /// /// 验证完整的微信支付响应格式与PHP API一致 /// Requirements: 10.1-10.4 /// [Fact] public void CompleteWechatPayResponse_ShouldMatchPhpFormat() { // Arrange - 模拟PHP API返回的格式 // PHP: return ['status' => 1, 'data' => $res]; // $res = ['appId' => ..., 'timeStamp' => ..., 'nonceStr' => ..., 'package' => ..., 'signType' => ..., 'paySign' => ...] var result = new WechatPayResult { Status = 1, Msg = "success", Data = new WechatPayData { AppId = "wx1234567890abcdef", TimeStamp = "1735776000", NonceStr = "abc123def456", Package = "prepay_id=wx123456789", SignType = "MD5", PaySign = "ABCDEF1234567890", IsWeixin = 1 } }; // Act var json = JsonSerializer.Serialize(result, _jsonOptions); // Assert - 验证顶层结构 Assert.Contains("\"status\":1", json); Assert.Contains("\"msg\":\"success\"", json); Assert.Contains("\"data\":", json); // Assert - 验证支付参数字段名(与PHP一致) Assert.Contains("\"appId\":\"wx1234567890abcdef\"", json); Assert.Contains("\"timeStamp\":\"1735776000\"", json); Assert.Contains("\"nonceStr\":\"abc123def456\"", json); Assert.Contains("\"package\":\"prepay_id=wx123456789\"", json); Assert.Contains("\"signType\":\"MD5\"", json); Assert.Contains("\"paySign\":\"ABCDEF1234567890\"", json); Assert.Contains("\"is_weixin\":1", json); } /// /// 验证微信支付失败响应格式 /// Requirements: 10.1, 10.3 /// [Fact] public void WechatPayFailResponse_ShouldMatchPhpFormat() { // Arrange - 模拟PHP API返回的失败格式 // PHP: return ['status' => 0, 'msg' => '支付失败']; var result = new WechatPayResult { Status = 0, Msg = "网络故障,请稍后重试(支付参数错误)" }; // Act var json = JsonSerializer.Serialize(result, _jsonOptions); // Assert - 验证结构正确(不验证具体中文内容,因为JSON会转义Unicode) Assert.Contains("\"status\":0", json); Assert.Contains("\"msg\":", json); // data字段应该为null Assert.Contains("\"data\":null", json); // 验证反序列化后内容正确 var deserialized = JsonSerializer.Deserialize(json, _jsonOptions); Assert.NotNull(deserialized); Assert.Equal(0, deserialized.Status); Assert.Equal("网络故障,请稍后重试(支付参数错误)", deserialized.Msg); } /// /// 验证支付回调XML响应格式 /// Requirements: 10.1 /// [Fact] public void NotifyXmlResponse_ShouldMatchWechatFormat() { // Arrange - 微信要求的XML响应格式 var successXml = ""; var failXml = ""; // Assert - 验证XML格式正确 Assert.Contains("", successXml); Assert.Contains("", successXml); Assert.Contains("", failXml); } #endregion #region Lottery System Response Format Tests - Requirements 10.1-10.4 /// /// 验证PrizeOrderLogRequest使用snake_case /// Requirements: 10.2 /// [Fact] public void LotteryPrizeOrderLogRequest_ShouldUseSnakeCase() { // Arrange var request = new HoneyBox.Model.Models.Lottery.PrizeOrderLogRequest { OrderNum = "TEST001" }; // Act var json = JsonSerializer.Serialize(request, _jsonOptions); // Assert Assert.Contains("\"order_num\":", json); Assert.DoesNotContain("\"OrderNum\":", json); } /// /// 验证InfiniteShangLogRequest使用snake_case /// Requirements: 10.2 /// [Fact] public void InfiniteShangLogRequest_ShouldUseSnakeCase() { // Arrange var request = new InfiniteShangLogRequest { GoodsId = 1, ShangId = 10, IsMibao = 0, Page = 1, PageSize = 10 }; // Act var json = JsonSerializer.Serialize(request, _jsonOptions); // Assert Assert.Contains("\"goods_id\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"is_mibao\":", json); Assert.Contains("\"page\":", json); Assert.Contains("\"page_size\":", json); } /// /// 验证DailyPrizeRecordsRequest使用snake_case /// Requirements: 10.2 /// [Fact] public void DailyPrizeRecordsRequest_ShouldUseSnakeCase() { // Arrange var request = new DailyPrizeRecordsRequest { GoodsId = 1, Page = 1, PageSize = 10 }; // Act var json = JsonSerializer.Serialize(request, _jsonOptions); // Assert Assert.Contains("\"goods_id\":", json); Assert.Contains("\"page\":", json); Assert.Contains("\"page_size\":", json); } /// /// 验证ItemCardDrawRequest使用snake_case /// Requirements: 10.2 /// [Fact] public void ItemCardDrawRequest_ShouldUseSnakeCase() { // Arrange var request = new ItemCardDrawRequest { GoodsId = 1, OrderListIds = "1,2,3" }; // Act var json = JsonSerializer.Serialize(request, _jsonOptions); // Assert Assert.Contains("\"goods_id\":", json); Assert.Contains("\"order_list_ids\":", json); } /// /// 验证InfiniteShangLogResponseDto使用snake_case /// Requirements: 10.2 /// [Fact] public void InfiniteShangLogResponseDto_ShouldUseSnakeCase() { // Arrange var dto = new InfiniteShangLogResponseDto { Category = new List { new() { ShangId = 0, ShangTitle = "全部" }, new() { ShangId = 10, ShangTitle = "A赏" } }, Data = new List(), LastPage = 1, Total = 10 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"category\":", json); Assert.Contains("\"data\":", json); Assert.Contains("\"last_page\":", json); Assert.Contains("\"total\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"shang_title\":", json); } /// /// 验证InfiniteShangLogItemDto使用snake_case /// Requirements: 10.2 /// [Fact] public void InfiniteShangLogItemDto_ShouldUseSnakeCase() { // Arrange var dto = new InfiniteShangLogItemDto { Id = 1, UserId = 1, GoodslistTitle = "测试奖品", GoodslistImgurl = "http://test.com/img.jpg", GoodslistPrice = "100.00", GoodslistMoney = "50.00", ShangId = 10, ShangTitle = "A赏", ShangColor = "#FF0000", PrizeNum = 1, Addtime = "2024-01-01 12:00:00", LuckNo = 1, Doubling = 1, IsLingzhu = 0, UserInfo = new LotteryUserInfoDto { Nickname = "测***户", HeadImg = "avatar.jpg" } }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"id\":", json); Assert.Contains("\"user_id\":", json); Assert.Contains("\"goodslist_title\":", json); Assert.Contains("\"goodslist_imgurl\":", json); Assert.Contains("\"goodslist_price\":", json); Assert.Contains("\"goodslist_money\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"shang_title\":", json); Assert.Contains("\"shang_color\":", json); Assert.Contains("\"prize_num\":", json); Assert.Contains("\"addtime\":", json); Assert.Contains("\"luck_no\":", json); Assert.Contains("\"doubling\":", json); Assert.Contains("\"is_lingzhu\":", json); Assert.Contains("\"user_info\":", json); Assert.Contains("\"nickname\":", json); Assert.Contains("\"headimg\":", json); } /// /// 验证DailyPrizeRecordItemDto使用snake_case /// Requirements: 10.2 /// [Fact] public void DailyPrizeRecordItemDto_ShouldUseSnakeCase() { // Arrange var dto = new DailyPrizeRecordItemDto { Id = 1, UserId = 1, GoodslistTitle = "测试奖品", GoodslistImgurl = "http://test.com/img.jpg", ShangId = 10, ShangTitle = "A赏", Addtime = "2024-01-01 12:00:00" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"id\":", json); Assert.Contains("\"user_id\":", json); Assert.Contains("\"goodslist_title\":", json); Assert.Contains("\"goodslist_imgurl\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"shang_title\":", json); Assert.Contains("\"addtime\":", json); } /// /// 验证InfinitePrizeRecordsResponseDto使用snake_case /// Requirements: 10.2 /// [Fact] public void InfinitePrizeRecordsResponseDto_ShouldUseSnakeCase() { // Arrange var dto = new InfinitePrizeRecordsResponseDto { Data = new List(), CurrentPage = 1, LastPage = 10, PerPage = 10, Total = 100 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"data\":", json); Assert.Contains("\"current_page\":", json); Assert.Contains("\"last_page\":", json); Assert.Contains("\"per_page\":", json); Assert.Contains("\"total\":", json); } /// /// 验证InfinitePrizeRecordItemDto使用snake_case /// Requirements: 10.2 /// [Fact] public void InfinitePrizeRecordItemDto_ShouldUseSnakeCase() { // Arrange var dto = new InfinitePrizeRecordItemDto { UserId = 1, GoodslistTitle = "测试奖品", GoodslistImgurl = "http://test.com/img.jpg", Addtime = "2024-01-01 12:00:00" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"user_id\":", json); Assert.Contains("\"goodslist_title\":", json); Assert.Contains("\"goodslist_imgurl\":", json); Assert.Contains("\"addtime\":", json); } /// /// 验证ItemCardDrawResponseDto使用snake_case /// Requirements: 10.2 /// [Fact] public void ItemCardDrawResponseDto_ShouldUseSnakeCase() { // Arrange var dto = new ItemCardDrawResponseDto { Status = 0, OrderNum = "TEST001", Prizes = new List { new() { Id = 1, Title = "测试奖品", ImgUrl = "http://test.com/img.jpg", ShangId = 10, ShangTitle = "A赏", ShangColor = "#FF0000", Price = "100.00", ScMoney = "50.00", PrizeCode = "PRIZE001", LuckNo = 1 } }, RemainingCards = 5 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"status\":", json); Assert.Contains("\"order_num\":", json); Assert.Contains("\"prizes\":", json); Assert.Contains("\"remaining_cards\":", json); Assert.Contains("\"id\":", json); Assert.Contains("\"title\":", json); Assert.Contains("\"img_url\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"shang_title\":", json); Assert.Contains("\"shang_color\":", json); Assert.Contains("\"price\":", json); Assert.Contains("\"sc_money\":", json); Assert.Contains("\"prize_code\":", json); Assert.Contains("\"luck_no\":", json); } /// /// 验证PrizeOrderLogResponseDto使用snake_case /// Requirements: 10.2 /// [Fact] public void PrizeOrderLogResponseDto_ShouldUseSnakeCase() { // Arrange var dto = new PrizeOrderLogResponseDto { Data = new List { new() { Id = 1, UserId = 1, GoodsListTitle = "测试奖品", GoodsListImgUrl = "http://test.com/img.jpg", GoodsListPrice = "100.00", GoodsListMoney = "50.00", Status = 0, LuckNo = 1, ShangId = 10, ShangTitle = "A赏", Doubling = 1, IsLingzhu = 0, GoodsListType = 1, GoodsListId = 1, ParentGoodsListId = 0, PrizeNum = 1, AddTime = 1234567890 } }, ItemCardCount = 5, PrizeNum = 1 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"data\":", json); Assert.Contains("\"item_card_count\":", json); Assert.Contains("\"prize_num\":", json); Assert.Contains("\"id\":", json); Assert.Contains("\"user_id\":", json); Assert.Contains("\"goodslist_title\":", json); Assert.Contains("\"goodslist_imgurl\":", json); Assert.Contains("\"goodslist_price\":", json); Assert.Contains("\"goodslist_money\":", json); Assert.Contains("\"status\":", json); Assert.Contains("\"luck_no\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"shang_title\":", json); Assert.Contains("\"doubling\":", json); Assert.Contains("\"is_lingzhu\":", json); Assert.Contains("\"goodslist_type\":", json); Assert.Contains("\"goodslist_id\":", json); Assert.Contains("\"parent_goods_list_id\":", json); Assert.Contains("\"addtime\":", json); } /// /// 验证InfinitePrizeOrderLogResponseDto使用snake_case /// Requirements: 10.2 /// [Fact] public void InfinitePrizeOrderLogResponseDto_ShouldUseSnakeCase() { // Arrange var dto = new InfinitePrizeOrderLogResponseDto { UserInfo = new UserBasicInfoDto { Nickname = "测试用户", HeadImg = "avatar.jpg" }, Data = new List(), ItemCardCount = 5, PrizeNum = 1 }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"user_info\":", json); Assert.Contains("\"data\":", json); Assert.Contains("\"item_card_count\":", json); Assert.Contains("\"prize_num\":", json); Assert.Contains("\"nickname\":", json); Assert.Contains("\"headimg\":", json); } /// /// 验证完整的无限赏中奖记录响应格式与PHP API一致 /// Requirements: 10.1-10.4 /// [Fact] public void CompleteInfiniteShangLogResponse_ShouldMatchPhpFormat() { // Arrange - 模拟PHP API返回的格式 var data = new InfiniteShangLogResponseDto { Category = new List { new() { ShangId = 0, ShangTitle = "全部" }, new() { ShangId = 10, ShangTitle = "A赏" } }, Data = new List { new() { Id = 1, UserId = 1, GoodslistTitle = "测试奖品", GoodslistImgurl = "http://test.com/img.jpg", GoodslistPrice = "100.00", GoodslistMoney = "50.00", ShangId = 10, ShangTitle = "A赏", ShangColor = "#FF0000", PrizeNum = 1, Addtime = "2024-01-01 12:00:00", LuckNo = 1, Doubling = 1, IsLingzhu = 0, UserInfo = new LotteryUserInfoDto { Nickname = "测***户", HeadImg = "avatar.jpg" } } }, LastPage = 1, Total = 1 }; var response = ApiResponse.Success(data); // Act var json = JsonSerializer.Serialize(response, _jsonOptions); // Assert - 验证顶层结构 Assert.Contains("\"status\":1", json); Assert.Contains("\"msg\":\"success\"", json); Assert.Contains("\"data\":", json); // Assert - 验证数据字段使用snake_case Assert.Contains("\"category\":", json); Assert.Contains("\"last_page\":", json); Assert.Contains("\"total\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"shang_title\":", json); Assert.Contains("\"user_id\":", json); Assert.Contains("\"goodslist_title\":", json); Assert.Contains("\"goodslist_imgurl\":", json); Assert.Contains("\"goodslist_price\":", json); Assert.Contains("\"goodslist_money\":", json); Assert.Contains("\"shang_color\":", json); Assert.Contains("\"prize_num\":", json); Assert.Contains("\"addtime\":", json); Assert.Contains("\"luck_no\":", json); Assert.Contains("\"doubling\":", json); Assert.Contains("\"is_lingzhu\":", json); Assert.Contains("\"user_info\":", json); Assert.Contains("\"nickname\":", json); Assert.Contains("\"headimg\":", json); } /// /// 验证完整的道具卡抽奖响应格式与PHP API一致 /// Requirements: 10.1-10.4 /// [Fact] public void CompleteItemCardDrawResponse_ShouldMatchPhpFormat() { // Arrange var data = new ItemCardDrawResponseDto { Status = 0, OrderNum = "MH_20240101120000001", Prizes = new List { new() { Id = 1, Title = "A赏奖品", ImgUrl = "http://test.com/prize.jpg", ShangId = 10, ShangTitle = "A赏", ShangColor = "#FF0000", Price = "100.00", ScMoney = "50.00", PrizeCode = "PRIZE20240101001", LuckNo = 88 } }, RemainingCards = 4 }; var response = ApiResponse.Success(data, "重抽成功"); // Act var json = JsonSerializer.Serialize(response, _jsonOptions); // Assert - 验证顶层结构 Assert.Contains("\"status\":1", json); Assert.Contains("\"data\":", json); // Assert - 验证数据字段使用snake_case Assert.Contains("\"order_num\":", json); Assert.Contains("\"prizes\":", json); Assert.Contains("\"remaining_cards\":", json); Assert.Contains("\"img_url\":", json); Assert.Contains("\"shang_id\":", json); Assert.Contains("\"shang_title\":", json); Assert.Contains("\"shang_color\":", json); Assert.Contains("\"sc_money\":", json); Assert.Contains("\"prize_code\":", json); Assert.Contains("\"luck_no\":", json); } /// /// 验证抽奖系统失败响应格式 /// Requirements: 10.1, 10.3 /// [Fact] public void LotteryFailResponse_ShouldMatchPhpFormat() { // Arrange - 模拟PHP API返回的失败格式 var response = ApiResponse.Fail("盒子不存在"); // Act var json = JsonSerializer.Serialize(response, _jsonOptions); // Assert Assert.Contains("\"status\":0", json); Assert.Contains("\"msg\":", json); // 验证反序列化后内容正确 var deserialized = JsonSerializer.Deserialize>(json, _jsonOptions); Assert.NotNull(deserialized); Assert.Equal(0, deserialized.Status); Assert.Equal("盒子不存在", deserialized.Msg); } /// /// 验证ShangInfoDto使用snake_case(用于赏品等级信息) /// Requirements: 10.2 /// [Fact] public void ShangInfoDto_ShouldUseSnakeCase() { // Arrange var dto = new ShangInfoDto { Id = 10, Title = "A赏", ImgUrl = "http://test.com/shang.jpg", Color = "#FF0000", SpecialImgUrl = "http://test.com/special.jpg" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"id\":", json); Assert.Contains("\"title\":", json); Assert.Contains("\"img_url\":", json); Assert.Contains("\"color\":", json); Assert.Contains("\"special_img_url\":", json); } /// /// 验证LotteryUserInfoDto使用snake_case /// Requirements: 10.2 /// [Fact] public void LotteryUserInfoDto_ShouldUseSnakeCase() { // Arrange var dto = new LotteryUserInfoDto { Nickname = "测***户", HeadImg = "avatar.jpg" }; // Act var json = JsonSerializer.Serialize(dto, _jsonOptions); // Assert Assert.Contains("\"nickname\":", json); Assert.Contains("\"headimg\":", json); } #endregion }