如何测试Blazor WASM中的自定义验证组件?
如何测试Blazor WASM的CustomValidation组件
我有一个Blazor WASM项目,准备编写测试用例。作为新手,我想了解如何测试以下CustomValidation组件?
public class CustomValidation : ComponentBase, IDisposable { private IDisposable? _subscriptions; private EditContext? _originalEditContext; [CascadingParameter] EditContext? CurrentEditContext { get; set; } [Parameter] public bool DoEditValidation { get; set; } = false; /// <inheritdoc /> protected override void OnInitialized() { if (CurrentEditContext == null) { throw new InvalidOperationException($"{nameof(DataAnnotationsValidator)} requires a cascading " + $"parameter of type {nameof(EditContext)}. For example, you can use {nameof(DataAnnotationsValidator)} " + $"inside an EditForm."); } _subscriptions = CurrentEditContext.EnableCustomValidation(DoEditValidation, true); _originalEditContext = CurrentEditContext; } public void Dispose() { _subscriptions?.Dispose(); } }
我尝试使用Bunit编写测试:
public class CustomValidationTests : IDisposable { private CustomValidation _customValidation; public CustomValidationTests() { _customValidation = new CustomValidation(); } [Fact] public void OnInitialized_SubscribesToCustomValidation() { // Arrange using var ctx = new TestContext(); var editContext = new EditContext(new object()); // Act var cut = ctx.RenderComponent<CustomValidation>( builder => builder.Add(c => c.CurrentEditContext, editContext)); // Assert Assert.NotNull(cut.Instance.CurrentEditContext); } }
但出现错误,原因是CurrentEditContext标记为CascadingParameter属性,存在访问权限问题。
问题原因
直接通过RenderComponent的Add方法传递CascadingParameter是错误用法。CascadingParameter是级联参数,需要通过级联传递的方式提供,而非像普通[Parameter]那样直接赋值。
正确测试方案
方案1:通过TestContext注册级联值
使用TestContext.AddCascadingValue方法注册EditContext,让组件能通过级联获取该参数:
public class CustomValidationTests : IDisposable { [Fact] public void OnInitialized_SubscribesToCustomValidation() { // Arrange using var ctx = new TestContext(); var model = new object(); var editContext = new EditContext(model); // 注册级联的EditContext ctx.AddCascadingValue(editContext); // Act var cut = ctx.RenderComponent<CustomValidation>(); // Assert Assert.NotNull(cut.Instance.CurrentEditContext); Assert.Equal(editContext, cut.Instance.CurrentEditContext); } [Fact] public void OnInitialized_ThrowsException_WhenNoEditContext() { // Arrange using var ctx = new TestContext(); // Act & Assert var exception = Assert.Throws<InvalidOperationException>(() => ctx.RenderComponent<CustomValidation>()); Assert.Contains("requires a cascading parameter of type EditContext", exception.Message); } [Fact] public void OnInitialized_UsesDoEditValidationParameter_Correctly() { // Arrange using var ctx = new TestContext(); var model = new object(); var editContext = new EditContext(model); var expectedDoEditValidation = true; bool actualDoEditValidation = false; bool actualSecondParam = false; // 模拟EnableCustomValidation方法,捕获传入的参数 IDisposable mockSubscription = Mock.Of<IDisposable>(); editContext.EnableCustomValidation = (doVal, secondParam) => { actualDoEditValidation = doVal; actualSecondParam = secondParam; return mockSubscription; }; ctx.AddCascadingValue(editContext); // Act ctx.RenderComponent<CustomValidation>( builder => builder.Add(c => c.DoEditValidation, expectedDoEditValidation)); // Assert Assert.Equal(expectedDoEditValidation, actualDoEditValidation); Assert.True(actualSecondParam); } public void Dispose() { // 清理测试资源 } }
方案2:用EditForm包裹组件
EditForm会自动向子组件级联EditContext,直接用EditForm包裹CustomValidation即可提供级联参数:
[Fact] public void OnInitialized_SubscribesToCustomValidation_WithEditForm() { // Arrange using var ctx = new TestContext(); var model = new object(); // Act var editForm = ctx.RenderComponent<EditForm>( builder => builder .Add(f => f.Model, model) .AddChildContent<CustomValidation>()); var customValidation = editForm.FindComponent<CustomValidation>(); // Assert Assert.NotNull(customValidation.Instance.CurrentEditContext); }
注意事项
- 若需要验证私有字段
_subscriptions或_originalEditContext,可选择以下方式:- 将字段改为
internal,并在项目文件中添加InternalsVisibleTo配置,允许测试项目访问内部成员; - 使用反射获取私有字段的值;
- 通过验证
EditContext的行为(比如模拟EnableCustomValidation的调用)间接验证订阅是否成功。
- 将字段改为
- 必须测试异常场景,确保组件在缺失级联
EditContext时抛出正确的异常。 - 如果
EnableCustomValidation是扩展方法,模拟其行为需要特殊处理,建议将核心逻辑封装到可注入的服务中,方便测试时替换。
内容的提问来源于stack exchange,提问作者ponti1907
相关产品推荐
相关产品推荐

