267 lines
8.5 KiB
C#
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());
|
|
}
|
|
}
|