使用bUnit编写MudBlazor单元测试遇MudPopover渲染空引用错误
问题
尝试用bUnit编写单元测试时,渲染组件因MudPopover报错失败,错误信息如下:
System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object. Source=MudBlazor StackTrace: at MudBlazor.MudPopover.BuildRenderTree(RenderTreeBuilder __builder) at Microsoft.AspNetCore.Components.ComponentBase.<.ctor>b__6_0(RenderTreeBuilder builder) at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException) --- End of stack trace from previous location --- at Bunit.Rendering.TestRenderer.AssertNoUnhandledExceptions() at Bunit.Rendering.TestRenderer.Render[TResult](RenderFragment renderFragment, Func`2 activator) at Bunit.Rendering.TestRenderer.RenderFragment(RenderFragment renderFragment) at Bunit.Extensions.TestContextBaseRenderExtensions.RenderInsideRenderTree(TestContextBase testContext, RenderFragment renderFragment) at Bunit.Extensions.TestContextBaseRenderExtensions.RenderInsideRenderTree[TComponent](TestContextBase testContext, RenderFragment renderFragment) at Bunit.TestContext.Render[TComponent](RenderFragment renderFragment) at Bunit.TestContext.RenderComponent[TComponent](Action`1 parameterBuilder)
随后尝试直接加载组件排查逻辑(代码如下),仍出现相同错误,求bUnit测试中Mock或初始化MudPopover的正确方法:
[Fact] public void TestRender() { var services = new ServiceCollection(); using var context = new TestContext(); services.AddMudServices(); services.AddSingleton<MudPopoverProvider>(); var mudPop = new Mock<MudPopover>(); var mudPoperProvider = new Mock<MudPopoverProvider>(); var mudPopService = new Mock<IMudPopoverService>(); mudPop.Setup(m => m.SetParametersAsync(new ParameterView())).Returns(Task.CompletedTask); context.Services.AddSingleton(mudPoperProvider.Object); context.Services.AddSingleton(mudPop.Object); context.Services.AddSingleton(mudPopService.Object); context.RenderComponent<MudPopoverProvider>(); context.RenderComponent<MudPopover>(); }
解决方案
核心问题
当前Mock方式存在两处错误:
MudPopover是Blazor组件而非服务,不能通过依赖注入注入Mock实例;- 手动创建的
ServiceCollection未关联到TestContext,导致AddMudServices()的配置未生效。
正确实现步骤
正确注册MudBlazor服务
无需单独创建ServiceCollection,直接在TestContext上配置MudBlazor服务即可,AddMudServices()已包含IMudPopoverService、MudPopoverProvider等必要服务的正确注册:using var context = new TestContext(); context.Services.AddMudServices();避免直接渲染MudPopover
MudPopover是MudBlazor的内部组件,依赖父组件传递的上下文参数(如PopoverId、Placement),单独渲染必然触发空引用异常。测试应聚焦于使用MudPopover的自定义组件,直接渲染该自定义组件即可。按需Mock IMudPopoverService
如果需要自定义弹出逻辑,可覆盖TestContext中的IMudPopoverService实例:var mockPopoverService = new Mock<IMudPopoverService>(); // 模拟弹出方法返回有效ID mockPopoverService.Setup(s => s.Show(It.IsAny<MudPopoverOptions>())).Returns(Guid.NewGuid()); // 替换TestContext中的服务 context.Services.AddSingleton(mockPopoverService.Object);完整测试示例
假设测试目标是包含MudPopover的自定义组件MyPopoverComponent:[Fact] public void TestCustomComponentWithMudPopover() { using var context = new TestContext(); // 注册MudBlazor服务 context.Services.AddMudServices(); // 可选:Mock弹出服务行为 var mockPopoverService = new Mock<IMudPopoverService>(); mockPopoverService.Setup(s => s.Show(It.IsAny<MudPopoverOptions>())).Returns(Guid.NewGuid()); context.Services.AddSingleton(mockPopoverService.Object); // 渲染自定义组件 var cut = context.RenderComponent<MyPopoverComponent>(); // 触发弹出动作并验证服务调用 cut.Find(".popover-trigger-btn").Click(); mockPopoverService.Verify(s => s.Show(It.IsAny<MudPopoverOptions>()), Times.Once); }
关键注意事项
- 无需测试
MudPopover本身,这类组件的正确性由MudBlazor官方测试保障,你的测试应聚焦于自身业务组件的逻辑。 AddMudServices()已自动处理MudPopoverProvider的初始化,无需手动注册或渲染该组件。
内容的提问来源于stack exchange,提问作者ist_lion
相关产品推荐
相关产品推荐

