HaniBlindBox/server/HoneyBox/tests/HoneyBox.Tests/Services/ResponseFormatPropertyTests.cs
2026-01-17 17:48:43 +08:00

267 lines
8.5 KiB
C#

using FsCheck;
using FsCheck.Xunit;
using HoneyBox.Admin.Business.Models;
using System.Text.Json;
using Xunit;
namespace HoneyBox.Tests.Services;
/// <summary>
/// 响应格式属性测试
/// Property 16: API Response Format Consistency - API响应格式一致性
/// Property 17: Paginated Response Format - 分页响应格式一致性
/// </summary>
public class ResponseFormatPropertyTests
{
/// <summary>
/// Property 16: ApiResponse 成功响应格式一致性
/// </summary>
[Property(MaxTest = 100)]
public bool Property16_ApiResponse_Success_HasConsistentFormat(PositiveInt seed)
{
var messages = new[] { "success", "操作成功", "OK", "完成" };
var message = messages[seed.Get % messages.Length];
var response = ApiResponse.Success(message);
return response.Code == 0 &&
response.Message == message &&
response.Data == null;
}
/// <summary>
/// Property 16: ApiResponse 带数据的成功响应格式一致性
/// </summary>
[Property(MaxTest = 100)]
public bool Property16_ApiResponse_SuccessWithData_HasConsistentFormat(PositiveInt seed)
{
var data = seed.Get;
var messages = new[] { "success", "操作成功", "OK" };
var message = messages[seed.Get % messages.Length];
var response = ApiResponse.Success(data, message);
return response.Code == 0 &&
response.Message == message &&
response.Data != null &&
(int)response.Data == data;
}
/// <summary>
/// Property 16: ApiResponse 错误响应格式一致性
/// </summary>
[Property(MaxTest = 100)]
public bool Property16_ApiResponse_Error_HasConsistentFormat(PositiveInt seed)
{
var code = (seed.Get % 1000) + 1; // Non-zero code
var messages = new[] { "error", "失败", "错误" };
var message = messages[seed.Get % messages.Length];
var response = ApiResponse.Error(code, message);
return response.Code == code &&
response.Message == message &&
response.Data == null;
}
/// <summary>
/// Property 16: ApiResponse<T> 泛型成功响应格式一致性
/// </summary>
[Property(MaxTest = 100)]
public bool Property16_GenericApiResponse_Success_HasConsistentFormat(PositiveInt seed)
{
var data = seed.Get;
var response = ApiResponse<int>.Success(data);
return response.Code == 0 &&
response.Message == "success" &&
response.Data == data;
}
/// <summary>
/// Property 16: ApiResponse<T> 泛型错误响应格式一致性
/// </summary>
[Property(MaxTest = 100)]
public bool Property16_GenericApiResponse_Error_HasConsistentFormat(PositiveInt seed)
{
var code = (seed.Get % 1000) + 1;
var messages = new[] { "error", "失败", "错误" };
var message = messages[seed.Get % messages.Length];
var response = ApiResponse<int>.Error(code, message);
return response.Code == code &&
response.Message == message &&
EqualityComparer<int>.Default.Equals(response.Data, default);
}
/// <summary>
/// Property 17: PagedResult 分页响应格式一致性
/// </summary>
[Property(MaxTest = 100)]
public bool Property17_PagedResult_HasConsistentFormat(PositiveInt seed)
{
var page = (seed.Get % 10) + 1;
var pageSize = (seed.Get % 50) + 1;
var total = seed.Get % 1000;
var items = Enumerable.Range(1, Math.Min(pageSize, Math.Max(0, total - (page - 1) * pageSize))).ToList();
var result = new PagedResult<int>
{
Page = page,
PageSize = pageSize,
Total = total,
List = items
};
// 验证分页结果格式
return result.Page == page &&
result.PageSize == pageSize &&
result.Total == total &&
result.List != null &&
result.List.Count <= pageSize;
}
/// <summary>
/// Property 17: PagedResult 总页数计算正确性
/// </summary>
[Property(MaxTest = 100)]
public bool Property17_PagedResult_TotalPages_CalculatedCorrectly(PositiveInt seed)
{
var pageSize = (seed.Get % 100) + 1;
var total = seed.Get % 10000;
var result = new PagedResult<int>
{
Page = 1,
PageSize = pageSize,
Total = total,
List = new List<int>()
};
var expectedTotalPages = (int)Math.Ceiling((double)total / pageSize);
return result.TotalPages == expectedTotalPages;
}
/// <summary>
/// Property 17: PagedResult 空结果处理
/// </summary>
[Fact]
public void Property17_PagedResult_EmptyResult_HasCorrectFormat()
{
var result = new PagedResult<int>
{
Page = 1,
PageSize = 20,
Total = 0,
List = new List<int>()
};
Assert.Equal(1, result.Page);
Assert.Equal(20, result.PageSize);
Assert.Equal(0, result.Total);
Assert.Equal(0, result.TotalPages);
Assert.Empty(result.List);
}
/// <summary>
/// Property 16: BusinessErrorCodes 错误码唯一性
/// </summary>
[Fact]
public void Property16_BusinessErrorCodes_AreUnique()
{
var errorCodes = new[]
{
BusinessErrorCodes.ValidationFailed,
BusinessErrorCodes.NotFound,
BusinessErrorCodes.AuthenticationFailed,
BusinessErrorCodes.PermissionDenied,
BusinessErrorCodes.InternalError
};
var uniqueCodes = errorCodes.Distinct().ToList();
Assert.Equal(errorCodes.Length, uniqueCodes.Count);
}
/// <summary>
/// Property 16: BusinessErrorCodes 错误码非零
/// </summary>
[Fact]
public void Property16_BusinessErrorCodes_AreNonZero()
{
var errorCodes = new[]
{
BusinessErrorCodes.ValidationFailed,
BusinessErrorCodes.NotFound,
BusinessErrorCodes.AuthenticationFailed,
BusinessErrorCodes.PermissionDenied,
BusinessErrorCodes.InternalError
};
foreach (var code in errorCodes)
{
Assert.NotEqual(0, code);
}
}
/// <summary>
/// Property 16: ApiResponse JSON 序列化格式一致性
/// </summary>
[Fact]
public void Property16_ApiResponse_JsonSerialization_HasExpectedFormat()
{
var response = ApiResponse.Success("test data", "操作成功");
var json = JsonSerializer.Serialize(response, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
Assert.True(root.TryGetProperty("code", out var codeElement));
Assert.True(root.TryGetProperty("message", out var messageElement));
Assert.True(root.TryGetProperty("data", out var dataElement));
Assert.Equal(0, codeElement.GetInt32());
Assert.Equal("操作成功", messageElement.GetString());
Assert.Equal("test data", dataElement.GetString());
}
/// <summary>
/// Property 17: PagedResult JSON 序列化格式一致性
/// </summary>
[Fact]
public void Property17_PagedResult_JsonSerialization_HasExpectedFormat()
{
var result = new PagedResult<string>
{
Page = 1,
PageSize = 10,
Total = 100,
List = new List<string> { "item1", "item2" }
};
var json = JsonSerializer.Serialize(result, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
Assert.True(root.TryGetProperty("page", out var pageElement));
Assert.True(root.TryGetProperty("pageSize", out var pageSizeElement));
Assert.True(root.TryGetProperty("total", out var totalElement));
Assert.True(root.TryGetProperty("totalPages", out var totalPagesElement));
Assert.True(root.TryGetProperty("list", out var listElement));
Assert.Equal(1, pageElement.GetInt32());
Assert.Equal(10, pageSizeElement.GetInt32());
Assert.Equal(100, totalElement.GetInt32());
Assert.Equal(10, totalPagesElement.GetInt32());
Assert.Equal(2, listElement.GetArrayLength());
}
}