单元测试Blazor RenderFragment元素

6

我已经开始编写一个动态构建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);
        }

我收到的错误信息是:
断言失败 期望值:RenderFragment { 方法 = Void b__2_0(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder), 目标 = <>c { } } 实际值:RenderFragment { 方法 = Void b__0(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder), 目标 = <>c__DisplayClass0_0 { attribute = null, attributeContent = null, element = "p", elementContent = "" } }
我不明白为什么我的片段对象上的目标与结果上的目标不同。
2个回答

2
"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));

这是一段包含以下代码的测试渲染器部分:
protected RenderTreeFrame[] GetRenderTree(IComponent component)
        {
            var renderer = new TestRenderer();
            renderer.AttachComponent(component);
            component.SetParameters(ParameterCollection.Empty);
            return renderer.LatestBatchReferenceFrames;
        }

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

看了一下链接,它使用的命名空间是Microsoft.ASpNetCore.Components。而我使用的是Microsoft.ASpNetCore.Blazor。总的来说,我使用的是Microsoft.AspNetCore 2.1.2,这个版本没有Components命名空间。从链接和你的代码片段来看,GetRenderTree方法似乎很关键,但是我在任何地方都找不到它。我还在使用Blazor 0.7.0。 - bilpor
我遇到的问题是,在您提供的最新链接中,他们使用了Microsoft.AspNetCore.Components命名空间。这在2.1.2中不可用。我注意到他们提到了2.0。我将尝试根据您的RenderTreeFrame示例尝试一些东西,看看能否有所进展。 - bilpor
1
就像我之前说的那样,它们更改了命名空间,但是你感兴趣的类在Blazor 0.7.0中仍将存在 - 但在Microsoft.AspNetCore.Blazor命名空间中。 - Mister Magoo
我找到了如何测试我的方法。上面的代码示例有所帮助,但并不完全相同。 - bilpor
@bilpor,你在测试片段时使用了什么技术?我也想尝试类似的事情。谢谢! - rabz100
显示剩余3条评论

1
我发现有一个非常有用的库,用于对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组件单元测试

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接