对 Blazor RenderFragment 元素进行单元测试

Unit Testing a Blazor RenderFragment element

提问人:bilpor 提问时间:1/22/2019 最后编辑:Vibeeshan Mahadevabilpor 更新时间:5/12/2020 访问量:2825

问:

我已经开始编写一个动态构建 RenderFragment 元素的方法。因此,我也在尝试与该方法一起编写单元测试。

我从一个非常基本的元素开始,但它失败了。以下是正在测试的具体方法:

public RenderFragment buildFragment(string element, string elementContent, string[] attribute, string[] attributeContent)
    {
        RenderFragment content = builder => {
            builder.OpenElement(0, element);
            if (attribute != null)
            {
                for (int i = 0; attribute.Length - 1 >= i; ++i)
                {
                    builder.AddAttribute(0, attribute[i], attributeContent[i]);
                }
            }
            if (!string.IsNullOrEmpty(elementContent))
            {
                builder.AddContent(0, elementContent);
            }
            builder.CloseElement();
        };

        return content;
    }

这是我对使用 xUnit 的方法进行的第一个基本测试:

public void BuildFragmentReturnsOneElement()
        {
            //Arrange
            RenderFragment fragment = builder =>
            {
                builder.OpenElement(0, "p");
                builder.CloseElement();
            };

            //Act
            RenderFragment result = _dynamicContentHelper.buildFragment("p", string.Empty, null, null);

            //Assert
            Assert.Same(fragment, result);
        }

我收到的错误是:

消息:Assert.Same() 失败 预期:RenderFragment { Method = void b__2_0(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder), Target = <>c { } } 实际:RenderFragment { Method = void b__0(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder), Target = <>c__DisplayClass0_0 { attribute = null, attributeContent = null, element = “p”, elementContent = “” } }

我不明白为什么我的片段对象上的 Target结果上的 Target 不同。

C# xUnit Blazor

评论


答:

2赞 Mister Magoo 1/26/2019 #1

这是一个 Delegate 方法,因此当您编写如下代码时:RenderFragment

RenderFragment fragment = builder =>
            {
                builder.OpenElement(0, "p");
                builder.CloseElement();
            };

您不是在创建具体化工件,而是在声明一个可以调用的委托。

因此,代码正在比较两个委托,这两个委托显然不相同 - 它们指向两个不同的方法。Assert.Same(fragment, result);

我认为你应该调查 Blazor 源的“test”文件夹

本节可能会有所帮助

他们应用的技术是检查 RenderTree 的帧

// Act
var frames = GetRenderTree(component);

// Assert
Assert.Collection(
 frames,
 frame => AssertFrame.Component(frame, "Test.RenderChildContent", 2, 0),
 frame => AssertFrame.Attribute(frame, RenderTreeBuilder.ChildContent, 1),
 frame => AssertFrame.Markup(frame, "\n  <div></div>\n", 2));

此外,本节中有一个 TestRenderer,其中包含此代码

protected RenderTreeFrame[] GetRenderTree(IComponent component)
        {
            var renderer = new TestRenderer();
            renderer.AttachComponent(component);
            component.SetParameters(ParameterCollection.Empty);
            return renderer.LatestBatchReferenceFrames;
        }

看看他们是如何进行测试的,因为我无法在这里重现所有测试,但这些是关键......

评论

0赞 bilpor 1/30/2019
查看链接,这使用命名空间 Microsoft.ASpNetCore.Components。我正在使用 Microsoft.ASpNetCore.Blazor。通常,我使用的是 Microsoft.AspNetCore 2.1.2,它没有组件命名空间。从链接和您的代码片段来看,该方法似乎是关键,但我在任何地方都无法获得。我也在使用 Blazor 0.7.0GetRenderTree
0赞 Mister Magoo 1/30/2019
逻辑是一样的,他们只是改变了命名空间。您可以在渲染片段上使用 GetFrames,然后对其进行测试。
0赞 bilpor 1/30/2019
我在任何地方都看不到 GetFrames,你能确认一下这个命名空间吗?
0赞 Mister Magoo 1/30/2019
我已经更新了答案 - 完整的测试方法在我在 Github 上链接到的项目中 - 它太大了,无法在这里重现,但我强调的部分应该足以让你继续前进。
1赞 Mister Magoo 1/30/2019
就像我之前说的,他们更改了命名空间,但你感兴趣的类仍将存在于 Blazor 0.7.0 中 - 但在命名空间 Microsoft.AspNetCore.Blazor 中
1赞 Mihail Vladov 5/12/2020 #2

我发现有一个非常有用的库用于单元测试 Blazor 组件,名为 bUnit 库。测试编写起来非常简单。下面是验证按钮单击是否正常工作的示例。

[Fact]
public void TestCounter()
{
    // Arrange
    var cut = RenderComponent<Counter>();
    cut.Find("p").MarkupMatches("<p>Current count: 0</p>");

    // Act
    var element = cut.Find("button");
    element.Click();

    //Assert
    cut.Find("p").MarkupMatches("<p>Current count: 1</p>");
}

这是另一个例子,包括使用 JustMock Lite 模拟服务

[Fact]
public void TestFetchData_ForecastIsNull()
{
    // Arrange
    var weatherForecastServiceMock = Mock.Create<IWeatherForecastService>();
    Mock.Arrange(() => weatherForecastServiceMock.GetForecastAsync(Arg.IsAny<DateTime>()))
        .Returns(new TaskCompletionSource<WeatherForecast[]>().Task);
    Services.AddSingleton<IWeatherForecastService>(weatherForecastServiceMock);

    // Act
    var cut = RenderComponent<FetchData>();

    // Assert - that it renders the initial loading message
    var initialExpectedHtml = 
                @"<h1>Weather forecast</h1>
                <p>This component demonstrates fetching data from a service.</p>
                <p><em>Loading...</em></p>";
    cut.MarkupMatches(initialExpectedHtml);
}

这些示例来自博客文章使用 bUnit 和 JustMock 对 Blazor 组件进行单元测试