104 lines
4.8 KiB
C#
104 lines
4.8 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using MAX.Framework.Validation;
|
|
using Store.Users.Contracts.Dtos;
|
|
using Store.Users.Dtos;
|
|
|
|
namespace Store.Users.Tests;
|
|
|
|
/// <summary>验证公共工具,以及 User DTO 仅保留 Required 的模块约定。</summary>
|
|
public sealed class RequestValidatorTests
|
|
{
|
|
[Fact]
|
|
public void NullRequest_IsRejectedByBothEntrypoints()
|
|
{
|
|
Assert.Equal("request", Assert.Throws<ArgumentNullException>(() => RequestValidator.Validate(null)).ParamName);
|
|
Assert.Throws<ArgumentNullException>(() => RequestValidator.TryValidate(null, out _));
|
|
}
|
|
|
|
[Fact]
|
|
public void ValidDto_PassesWithoutChangingInput()
|
|
{
|
|
var request = new UserCreateRequest { UserName = " main ", Password = "password", Notes = "" };
|
|
RequestValidator.Validate(request);
|
|
Assert.True(RequestValidator.TryValidate(request, out var errors));
|
|
Assert.Empty(errors);
|
|
Assert.Equal(" main ", request.UserName);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void RequiredFields_RejectNullEmptyAndWhitespace(string? value)
|
|
{
|
|
var request = new UserFundsRequest { UserName = value!, RequestId = "id", Amount = 1m, Operation = "充值" };
|
|
var error = Assert.Throws<ValidationException>(() => RequestValidator.Validate(request));
|
|
Assert.Equal("目标账户不能为空", error.Message);
|
|
Assert.Contains(nameof(UserFundsRequest.UserName), error.ValidationResult!.MemberNames);
|
|
}
|
|
|
|
[Fact]
|
|
public void TryValidate_ReturnsAllMissingRequiredFields()
|
|
{
|
|
Assert.False(RequestValidator.TryValidate(new UserFundsRequest(), out var errors));
|
|
Assert.Equal(3, errors.Count);
|
|
Assert.Contains(errors, e => e.MemberNames.Contains(nameof(UserFundsRequest.UserName)));
|
|
Assert.Contains(errors, e => e.MemberNames.Contains(nameof(UserFundsRequest.RequestId)));
|
|
Assert.Contains(errors, e => e.MemberNames.Contains(nameof(UserFundsRequest.Operation)));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(UserFundsRequest))]
|
|
[InlineData(typeof(UserEditRequest))]
|
|
[InlineData(typeof(UserCreateRequest))]
|
|
[InlineData(typeof(ChangePasswordRequest))]
|
|
[InlineData(typeof(UserSearchRequest))]
|
|
[InlineData(typeof(UserRecordSearchRequest))]
|
|
[InlineData(typeof(UserTopUpMessageRequest))]
|
|
[InlineData(typeof(UserTopUpResultRequest))]
|
|
[InlineData(typeof(UserTopUpQrcodeRequest))]
|
|
[InlineData(typeof(UserNameRequest))]
|
|
[InlineData(typeof(UserLoginRequest))]
|
|
[InlineData(typeof(UserTopUpQrcodeQuery))]
|
|
[InlineData(typeof(ShopRenewRequest))]
|
|
public void UserDtos_DeclareOnlyRequiredValidation(Type type)
|
|
{
|
|
Assert.False(typeof(IValidatableObject).IsAssignableFrom(type));
|
|
foreach (var property in type.GetProperties())
|
|
Assert.All(property.GetCustomAttributes(typeof(ValidationAttribute), true), attribute => Assert.IsType<RequiredAttribute>(attribute));
|
|
}
|
|
|
|
[Fact]
|
|
public void UserDto_DoesNotCheckNonEmptyParameterValues()
|
|
{
|
|
// 这些值非空但不合法:DTO 应通过,服务负责拒绝。
|
|
RequestValidator.Validate(new UserFundsRequest { UserName = new string('u', 21), RequestId = "id", Amount = -1, Operation = "非法操作" });
|
|
RequestValidator.Validate(new UserTopUpQrcodeRequest { AgentCode = "agent", QrcodeBase64 = "invalid!" });
|
|
RequestValidator.Validate(new UserRecordSearchRequest { Page = 0, StartTime = new(2025, 2, 1), EndTime = new(2025, 1, 1) });
|
|
RequestValidator.Validate(new ShopRenewRequest { ShopId = "shop", RenewDuration = 0 });
|
|
RequestValidator.Validate(new UserCreateRequest { UserName = "user", Password = "123", ShopPointsPerMonth = 1 });
|
|
}
|
|
|
|
[Fact]
|
|
public void FrameworkValidator_StillSupportsOtherModulesAnnotationsAndCrossFieldRules()
|
|
{
|
|
// User 的约定不限制公共工具支持标准 DataAnnotations 的能力。
|
|
Assert.Throws<ValidationException>(() => RequestValidator.Validate(new OtherModuleRequest { Name = "toolong" }));
|
|
Assert.False(RequestValidator.TryValidate(new OtherModuleRequest { Name = "ok", Count = 0 }, out _));
|
|
var request = new OtherModuleRequest { Name = "ok", Count = 2, Start = 2, End = 1 };
|
|
Assert.Equal("顺序错误", Assert.Throws<ValidationException>(() => RequestValidator.Validate(request)).Message);
|
|
}
|
|
|
|
private sealed class OtherModuleRequest : IValidatableObject
|
|
{
|
|
[Required, StringLength(4)] public string Name { get; set; } = "";
|
|
[Range(1, 10)] public int Count { get; set; } = 1;
|
|
public int Start { get; set; }
|
|
public int End { get; set; }
|
|
public IEnumerable<ValidationResult> Validate(ValidationContext context)
|
|
{
|
|
if (Start > End) yield return new ValidationResult("顺序错误");
|
|
}
|
|
}
|
|
}
|