How-To: Write bUnit Tests for Pages with Parameters

Page routing parameters allow developers to pass data to pages in their URL. bUnit allows us to pass routing parameters to pages, so that we can validate their behavior with test data. These parameters are set as part of the TestContext rendering process. This works exactly the same way as testing component parameters.

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 page with routing parameters in our project. If we don’t already have one, we can create one using the steps in the How-To: Define Routing Parameters on Blazor Page article.

Page with Routing Parameters

First, let’s review the HTML markup and code from the page with routing parameters article (called PageWithParameters):

@page "/page-params/{Type}/{Id:int}"
@page "/page-params/{Type}"

<h3>Page With Parameter</h3>
<h5>Parameter Values:</h5>
<p>Type: @Type</p>
<p>Id: @Id</p>

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

    [Parameter]
    public int? Id { get; set; }
}

As we can see, we defined a couple of parameters on this page. And, we also defined a couple of routes using the @page attribute which maps segments of the URL to those parameters. The Razor routing sets those entries in the URL fragment to the matching parameter names.

Create Test Class

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

using Blazor.HowTo.Pages;
using Bunit;
using Xunit;

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

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

            // assert
            var expectedHtml =
@"  <h3>Page With Parameter</h3>
    <h5>Parameter Values:</h5>
    <p>Type:
    </p>
    <p>Id:
    </p>
";
            comp.MarkupMatches(expectedHtml);
        }

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

            // act
            var comp = ctx.RenderComponent<PageWithParameter>(parameters => parameters
                    .Add(p => p.Type, "TestType")
                    .Add(p => p.Id, 1001));

            // assert
            var expectedHtml =
@"  <h3>Page With Parameter</h3>
    <h5>Parameter Values:</h5>
    <p>Type: TestType
    </p>
    <p>Id: 1001
    </p>
";
            comp.MarkupMatches(expectedHtml);
        }

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

            // act
            var comp = ctx.RenderComponent<PageWithParameter>(parameters => parameters
                    .Add(p => p.Type, "TestType"));

            // assert
            var expectedHtml =
@"  <h3>Page With Parameter</h3>
    <h5>Parameter Values:</h5>
    <p>Type: TestType
    </p>
    <p>Id:
    </p>
";
            comp.MarkupMatches(expectedHtml);
        }
    }
}

The first test method (InitialRender – lines #9-28) creates and renders the page without any parameters, so their default values are used… for strings, that’s null or empty string. So this first rendering is very simple, but verifies that our page will render even when no routing parameters are set.

In the InitialRender_WithParameters test method (lines #30-51), we actually set both routing parameters and then render the page. Let’s see how that is done.

  1. We setup the bUnit TestContext as usual (line #34).
  2. We call the TestContext.RenderComponent method for the PageWithParameter type (line #37). But rather than using the empty argument 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 let’s define the parameters builder (also in line #37).
    • Add the Type parameter for our route (line #38).
    • Add the Id parameter for the route (line #39).
    • Notice that parameters builders use the Fluent API style, so we can chain Add calls for multiple parameters.
    • That’s all it takes… we have set all of our page routing parameters. And they will be used during the call to TestContext.RenderComponent.
  4. Then, we define the expected rendered HTML (lines #43-49)… 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 page markup matches our expectations.

Finally, the InitialRender_WithoutOptionalId test method (lines #53-73) verifies that our page rendering works correctly when the optional Id parameter isn’t set. Since the Id is an optional routing parameter, it is good to have a test for that condition. The structure of this test method matches the ones above.

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

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

In conclusion, we can pass routing parameters to pages 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 of our pages.

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