DEV Community

Kenichiro Nakamura
Kenichiro Nakamura

Posted on

DevOps Blazor WebAssembly Solution: Part 1 - Add Unit Test projects and use TestHost

As a C# developer, I love Blazor, but there are several things to consider.

  • WebAssembly is still in preview
  • No official unit test framework is supported (yet)

However, unit testing is essential to DevOps. Fortunately, Steve Sanderson published Unit testing Blazor components - a prototype back in Aug last year, so I use this to write unit test and do DevOps Blazor WebAssembly.

Blazor WebAssembly project

Follow the instruction here to create Blazor WebAssembly project. I believe you can do server side Blazor but I stick with WebAssembly this time :)

1. Install Microsoft.AspNetCore.Components.WebAssembly.Templates and create new project. Select Blazor App.
Alt Text

2. Select WebAssembly App. I decided to host this in ASP.NET Core.
Alt Text

3. Compile and the run the application to make sure it works fine.
Alt Text

Git clone testing repository

To use the testing library, I need to git clone as it's not published as NuGet.

git clone https://github.com/SteveSandersonMS/BlazorUnitTestingPrototype

Copy Microsoft.AspNetCore.Components.Testing to my project.
Alt Text

Add unit test project

The Testing prototype works with Unit Test project such as xUnit.

1. Add C# .NET Core xUnit Test project to the solution. I named it as "DevOpsBlazor.UnitTests".
Alt Text

2. Then add existing project by selecting Microsoft.AspNetCore.Components.Testing.csproj.
Alt Text

3. Finally, Add project references to xUnit project. As the server project has references to client and shared, I just added server and testing project.
Alt Text

4. Optionally, update all NuGet and compile entire solution to make sure there is no errors.

Add Unit Tests

The out of box application has several Blazor components. Let's start adding first unit test. Index.razor is the default page of the application. It just contains static information, so it should be good starting point.

Assert HTML Element

TestHost is a class which renders Blazor components like a browser. It provides several methods such as Find, FindAll to find HTML elements or GetMarkup to get generated HTML as string.

1. Rename existing UnitTest1.cs to IndexPageUnitTests.cs and change existing method name to "ShouldRenderHello".

using System;
using Xunit;

namespace DevOpsBlazor.UnitTests
{
    public class IndexPageUnitTests
    {
        [Fact]
        public void ShouldRenderHello()
        {

        }
    }
}

2. Add TestHost class property and solve using. The Blazor component will be rendered into this TestHost class and I can use it to assert various things.

TestHost host = new TestHost();

3. In ShouldRenderHello method, render the Index page. Now the component instance contains rendered results of Index.

var component = host.AddComponent<Client.Pages.Index>();

4. Let's assert h1 tag message. The Find method takes CSS selector and return first found element.

Assert.Equal("Hello, world!", component.Find("h1").InnerText);

5. Compile the solution, then run the test in Test Explorer.
Alt Text

Assert Child Component

Index.razor contains SurveyPrompt.razor as child component. Let's see how child components are rendered inside TestHost.

1. Put breakpoint at the Assert statement and run the test in debug mode.
Alt Text

2. See the result of component.GetMarkup() in Watch window.
Alt Text

3. I see child component is also rendered as pure HTML. Stop the debug and replace current assert.

// Assert h1
Assert.Equal("Hello, world!", component.Find("h1").InnerText);
// Assert text in the body
Assert.Contains("Welcome to your new app.", component.GetMarkup());
// Assert if survey component exists
Assert.NotNull(component.Find(".alert.alert-secondary"));
// Assert the link
Assert.Equal(
    "https://go.microsoft.com/fwlink/?linkid=2127212",
    component.Find("a").Attributes["href"].Value);

Work with parameters

Though I already test SurveyPrompt as part of Index, I should test this separately as it takes a parameter.

1. Add SurveyPromptUnitTests.cs to test project. Then replace the code as following.

using Microsoft.AspNetCore.Components.Testing;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace DevOpsBlazor.UnitTests
{
    public class SurveyPromptUnitTests
    {
        TestHost host = new TestHost();

        [Fact]
        public void ShouldRenderTitle()
        {

        }
    }
}

2. Render the component by passing Title parameter.

var title = "Test";
var parameters = new Dictionary<string, object>() { { "Title", title } };
var component = host.AddComponent<SurveyPrompt>(parameters);
Assert.Equal(title, component.Find("strong").InnerText);

3. Compile solution and run the test.
Alt Text

Summary

In this article, I simply added several unit tests to try using TestHost. In the next article, I will add more test which covers more scenarios.

Go to next article

Additional Information

I used BlazorUnitTestingPrototype this time, but there is another interesting unit test project called bunit. I will use this in the future too.

Top comments (1)

Collapse
 
kanachrisi profile image
kanachrisi

I am not able to run the tests shown in this demo because i am getting this exception error "System.MissingFieldException : Field not found: 'Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrame.FrameType'."
I have configured everything as described in the demo and i am using .Net 7. Could that be a problem ? Could you please share the source for this demo ?
Thank you for your feedback.