I've started to write a method for dynamically building a RenderFragment Element. As such I'm also trying to write Unit Tests alongside the method.
I'm starting with a very basic element and it fails. Here's the concrete method under test:
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;
}
This is my first basic test against the method using 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);
}
The error I receive is:
Message: Assert.Same() Failure Expected: RenderFragment { Method = Void b__2_0(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder), Target = <>c { } } Actual: RenderFragment { Method = Void b__0(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder), Target = <>c__DisplayClass0_0 { attribute = null, attributeContent = null, element = "p", elementContent = "" } }
I don't understand why Target on my fragment object is different from the Target on result.
The RenderFragment
is a Delegate method, so when you write code like this:
RenderFragment fragment = builder =>
{
builder.OpenElement(0, "p");
builder.CloseElement();
};
You are not creating a materialised artifact, but declaring a delegate that can be invoked.
The code Assert.Same(fragment, result);
is therefore comparing two delegates, which are clearly not the same - they point to two different methods.
I believe you should investigate the "test" folder of the Blazor Source
This section may help a lot
The technique they apply is to examine the frames of the 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));
Also, this section with a TestRenderer which has this code in it
protected RenderTreeFrame[] GetRenderTree(IComponent component)
{
var renderer = new TestRenderer();
renderer.AttachComponent(component);
component.SetParameters(ParameterCollection.Empty);
return renderer.LatestBatchReferenceFrames;
}
Have a look at how they do their tests as I cannot reproduce it all here, but those are the keys...
I found that there is a very useful library for unit testing Blazor components named bUnit library. The tests are very simple to be written. Here is an example of validating that a button click is working.
[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>");
}
And here is another example which includes mocking of service with 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);
}
The examples are from the blog post Unit Testing Blazor Components with bUnit and JustMock
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With