如何在无EditForm时测试包含InputText的_Item组件?
问题描述
遇到如下错误:
System.InvalidOperationException : Microsoft.AspNetCore.Components.Forms.InputText requires a cascading parameter of type EditContext. For example, you can use Microsoft.AspNetCore.Components.Forms.InputText inside an EditForm.
_Item组件代码:
@if (UtiliseItemCostum()) { <div class="form-group mt-3"> <label>Item</label> @if (EpicerieDetailsUtiliseItemCustom()) { <InputText id="itemNonEnregistre" @bind-Value="EpicerieDetailsDto.ItemCustom"></InputText> } else if (GabaritDetailsUtiliseItemCustom()) { <InputText id="itemNonEnregistre" @bind-Value="GabaritDetailsDto.ItemCustom"></InputText> } </div> } else { <_MenuDeroulantItems EpicerieDetailsDto="@EpicerieDetailsDto" GabaritDetailsDto="@GabaritDetailsDto" /> }
该组件在父组件的EditForm中可正常运行,父组件核心代码如下:
<EditForm Model="EpicerieDetailsDto" OnValidSubmit="GererEpicerieDetails"> <!-- 其他表单元素 --> <_Item EpicerieDetailsDto="@EpicerieDetailsDto"/> <!-- 其他表单元素 --> </EditForm>
但执行测试代码时,InputText因缺失EditContext报错,测试代码如下:
public static IEnumerable<TestCaseData> ItemTestCases() { yield return new TestCaseData(null, new EpicerieDetailsDto() { UtiliseItemCustom = true }); yield return new TestCaseData(new GabaritDetailsDto() { UtiliseItemCustom = true }, null); } [Test] [TestCaseSource(nameof(ItemTestCases))] public void QuandChangeCheckBox_AlorsChangeChoixItem(GabaritDetailsDto gabarit, EpicerieDetailsDto epicerie) { var cut = _testContext.RenderComponent<_Item>(parametres => parametres .Add(p => p.EpicerieDetailsDto, epicerie) .Add(p => p.GabaritDetailsDto, gabarit) ); Assert.NotNull(cut.Find("#itemNonEnregistre")); }
需求:通过模拟EditForm环境测试该含InputText的组件。
解决方案
要解决测试时EditContext缺失的问题,有两种可靠实现方式:
方式一:用EditForm包裹待测试组件
直接在测试中把_Item组件嵌套在EditForm内部,传入对应的Dto作为EditForm的Model,自动生成所需的EditContext。修改后的测试代码如下:
[Test] [TestCaseSource(nameof(ItemTestCases))] public void QuandChangeCheckBox_AlorsChangeChoixItem(GabaritDetailsDto gabarit, EpicerieDetailsDto epicerie) { // 确定EditForm使用的Model(和传入_Item的Dto一致) var formModel = epicerie ?? gabarit; var cut = _testContext.RenderComponent<EditForm>(parameters => parameters .Add(p => p.Model, formModel) .AddChildContent(_testContext.CreateComponent<_Item>(childParams => childParams .Add(p => p.EpicerieDetailsDto, epicerie) .Add(p => p.GabaritDetailsDto, gabarit) )) ); Assert.NotNull(cut.Find("#itemNonEnregistre")); }
方式二:手动传入CascadingValue
如果不需要完整的EditForm功能,可直接通过CascadingValue组件手动注入EditContext,模拟EditForm的核心依赖:
[Test] [TestCaseSource(nameof(ItemTestCases))] public void QuandChangeCheckBox_AlorsChangeChoixItem(GabaritDetailsDto gabarit, EpicerieDetailsDto epicerie) { var model = epicerie ?? gabarit; var editContext = new EditContext(model); var cut = _testContext.RenderComponent<CascadingValue<EditContext>>(parameters => parameters .Add(p => p.Value, editContext) .AddChildContent(_testContext.CreateComponent<_Item>(childParams => childParams .Add(p => p.EpicerieDetailsDto, epicerie) .Add(p => p.GabaritDetailsDto, gabarit) )) ); Assert.NotNull(cut.Find("#itemNonEnregistre")); }
注意事项
- 两种方式都要保证EditContext的Model和_Item组件使用的Dto完全一致,避免绑定异常。
- 如果组件依赖表单验证(如ValidationMessage),优先选择方式一,因为EditForm会自动初始化验证相关上下文。
内容的提问来源于stack exchange,提问作者Christoff Colomb
相关产品推荐
相关产品推荐

