How-To: Write bUnit Tests for Components with Parameters

Component parameters allow developers to build interactive and reusable Blazor components. bUnit provides us a couple of mechanisms for passing parameters to components, so that we can validate their behavior with test data. These parameters are set as part of the TestContext rendering process.

First, we must have a Blazor project and corresponding test project. Either open an existing solution or please follow the steps in the How-To: Add bUnit Test Project to Blazor Solution article to get both projects and all of the required packages. For this article, we called the projects: Blazor.HowTo and Blazor.HowTo.Tests.

Then, we need a Blazor component in our project. If we don’t already have one, we can create one using the steps in the How-To: Define Parameters on Blazor Component article.

Component With Parameters

First, let’s review the component markup and code from the component parameters article:

<div class="col-12 pt-1 rounded border"
     style="background-color: lightgray; cursor: pointer">
    <img class="float-left mr-2 mt-2 align-items-center" src="@ImageLink" />
    <h5><strong>@Title</strong></h5>
    <p style="font-size: small">
        @ChildContent
    </p>
</div>

@code {
    [Parameter]
    public string Title { get; set; }

    [Parameter]
    public string ImageLink { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }
}

As we can see, we defined 3 component parameters for parent components to set and which are data-bound into the component rendering.

Create Test Class

Now, let’s create the BannerAdTests class in the Blazor.HowTo.Tests project and Components folder.

using Blazor.HowTo.Components;
using Bunit;
using Xunit;

namespace Blazor.HowTo.Tests.Components
{
    public class BannerAdTests
    {
        [Fact]
        public void InitialRender()
        {
            // arrange
            var ctx = new TestContext();

            // act
            var comp = ctx.RenderComponent<BannerAd>();

            // assert
            var expectedHtml =
@"  <div class=""col-12 pt-1 rounded border"" style=""background-color: lightgray; cursor: pointer"">
      <img class=""float-left mr-2 mt-2 align-items-center"">
      <h5>
        <strong></strong>
      </h5>
      <p style=""font-size: small""></p>
    </div>
";
            comp.MarkupMatches(expectedHtml);
        }

        [Fact]
        public void InitialRender_WithParameters()
        {
            // arrange
            var ctx = new TestContext();

            // act
            var comp = ctx.RenderComponent<BannerAd>(parameters => parameters
                    .Add(p => p.Title, "Test Ad")
                    .Add(p => p.ImageLink, "/foo/test.png")
                    .AddChildContent("Test <strong>ad</strong> description.")
                );

            // assert
            var expectedHtml =
@"  <div class=""col-12 pt-1 rounded border""
         style=""background-color: lightgray; cursor: pointer"">
      <img class=""float-left mr-2 mt-2 align-items-center""
           src=""/foo/test.png"">
      <h5>
        <strong>Test Ad</strong>
      </h5>
      <p style=""font-size: small"">Test <strong>ad</strong> description.</p>
    </div>
";
            comp.MarkupMatches(expectedHtml);
        }
}

The first test method (InitialRender – lines #9-20) creates and renders the component without any parameters, so their default values are used… for strings, that’s null or empty strings. So this first rendering is very simple with no image source, no title, and no description. But we have verified that our component will render even when no parameters are set.

In the InitialRender_WithParameters test method (lines #31-57), we actually set the component parameters and then render it. Let’s see how that is done.

  1. We setup the bUnit TestContext as usual (line #35).
  2. We call the TestContext.RenderComponent method for the BannerAd type (line #38). But rather than using the empty parameter overload of this method, we use the method that takes a list of component parameters.
  3. I prefer to use the builder notation for adding parameters, so we define the parameters builder (also in line #38).
    • Add the Title parameter for our component (line #39).
    • Add the ImageLink parameter for the component (line #40).
    • There is a separate method to add the ChildContent parameter to the component (line #41). And we are defining the child content with simple HTML markup to show that is possible to accept and render.
    • Notice that parameters uses the Fluent API style, so we can chain Add calls for multiple parameters.
    • That’s all it takes… we are set all of our component parameters. And they will be used during the call to TestContext.RenderComponent.
  4. Then, we define the expected rendered HTML (lines #45-55)… notice that we’ve added the parameter values to the output from the empty rendering.
  5. Finally, we use the MarkupMatches validation method to ensure that the component markup matches our expectations.

We can follow these steps for any number and types of component parameters. This ability to simply pass parameters to a component under test is a powerful testability feature in bUnit.

Finally, let’s launch the new tests in the Visual Studio TestExplorer and verify that they pass as we expect.

In conclusion, we can pass component parameters to components in the bUnit TestContext.RenderComponent method. There are different ways to pass parameters to this method, but the parameter builder construct is the easiest to use. We can pass various different parameter values in separate tests, if we have rendering logic that is based on their values (or existence). So, this mechanism allows us to fully test the states in our components.

One thought on “How-To: Write bUnit Tests for Components with Parameters

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s