The implementation of the Unit test helps us to keep high quality in our project, especially, when we have to perform changes or update logic.
For .net we have some libraries to implement unit testing like NUnit, xUnit, and MSTest.
bUnit is a project that is part of .net foundation. It’s open-source, free, and easy to use. And it’s the perfect tool to implement a unit test for components in Blazor.
To use bUnit We need to install the NuGet package and also use a library for unit testing like xUnit:
Example test project configuration,
<ItemGroup>
<PackageReference Include="bunit" Version="1.1.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
Let’s see this simple demo,
The following code is a Blazor component,
<h1>Counter</h1>
<p>
Current count: @currentCount
</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
}
}
We can create a unit test for this simple component. Using TextContest we can get the UI related to the Counter component and perform actions like Click over the HTML elements and then evaluate the side effect in the component. For example, the element p with the text “<p>Current count: 1</p>”
The attribute [Fact] means that this method is a Unit test using the xUnit library.
[Fact]
public void CounterShouldIncrementWhenClicked()
{
// Arrange: render the Counter.razor component
using var ctx = new TestContext();
var cut = ctx.RenderComponent<Counter>();
// Act: find and click the <button> element to increment
// the counter in the <p> element
cut.Find("button").Click();
// Assert: first find the <p> element, then verify its content
cut.Find("p").MarkupMatches("<p>Current count: 1</p>");
}
This is a simple demo but we can also implement this unit test for other scenarios.
Take a look at this Component,
@page "/counter"
<h1>Counter</h1>
<p>Current count: @vm.currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
And this is the code file associated to the component,
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using blazor5dotnet.ViewModels; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Logging; namespace blazor5dotnet.Pages.Counter { public partial class Counter : ComponentBase { [Inject] ILogger<Counter> logger {get;set;} [Inject] CounterViewModel vm {get;set;} protected override void OnInitialized() { logger.LogInformation("Initializing component"); } private void IncrementCount() { logger.LogInformation($"increment count in 1 {vm.currentCount}"); vm.currentCount++; logger.LogInformation($"value incremented {vm.currentCount}"); } } }
In this scenario, we have some dependencies on the component that we need to set before any other action.
We can use the section Services to add the dependencies easily and also we can use the Moq library to create mocks for these dependencies.
[Fact]
public void CounterIncrese()
{
using var ctx = new TestContext();
ctx.Services.AddSingleton<ILogger<Counter>, Logger<Counter>>();
ctx.Services.AddSingleton(new CounterViewModel());
var component = ctx.RenderComponent<Counter>();
var parElement = component.Find("p");
component.Find("button").Click();
var elementResult = parElement.TextContent;
parElement.MarkupMatches("<p>Current count: 1</p>");
}
Go to Mteheran/Blazor5NetUniversity: Blazor5NetUniversity (github.com) to check this example.