Table of Contents

Controlling component instantiation

Components are, by default in bUnit, instantiated in the exact same way the regular Blazor runtime does it. For example, if the component under test has a <Counter /> component inside it, an instance of the Counter class will be created at runtime and added to the render tree below the component under test.

It is however possible to control how Blazor components build using .NET 5 or newer are instantiated by bUnit. This enables the possibility to replace one component during testing with another, e.g., to replace a 3rd party component during testing with a "stub component", to make the test easier to write and maintain.

The following sections will describe how to use component factories to control the instantiation of components during testing.

Using component factories to control instantiation

To take control of how components are instantiated during testing, add one or more IComponentFactory types to the ComponentFactories collection.

The added component factories CanCreate(Type) methods will be called in a last- to first-added order, e.g., the last one added will be called first, then the second-to-last, and so on, and the first that returns true will have its Create(Type) method invoked. If none of the factories can create the requested type, the default Blazor factory will be used.

Example – replacing <Foo> with <Bar>

To create a component factory that replaces <Foo> with <Bar> create the following component factory:

{
  using System;
  using Microsoft.AspNetCore.Components;
  using Bunit;

  public class FooBarComponentFactory : IComponentFactory
  {
    public bool CanCreate(Type componentType)
      => typeof(Foo) == componentType;

    public IComponent Create(Type componentType)
      => new Bar();

Make sure that the replacement component is compatible with the component it replaces, i.e., has the same parameters. This can be done by copying all parameters from the replacee to the replacer, or by using attribute splatting and arbitrary parameters in the replacer.

Then, before rendering the component under test, add the FooBarComponentFactory to the test context’s component factories collection:

  public class ComponentFactoryExampleTest : TestContext
  {
    [Fact]
    public void ReplacesFooWithBarDuringTest()
    {
      // Arrange
      ComponentFactories.Add(new FooBarComponentFactory());

      // Act
      var cut = RenderComponent<Wrapper>(parameters => parameters
        .AddChildContent<Foo>());

      // Assert that there are no <Foo> in render tree,
      // but there is one <Bar> in the render tree.
      Assert.Empty(cut.FindComponents<Foo>());
      Assert.Equal(1, cut.FindComponents<Bar>().Count);
    }
  }
}

Built-in factories

bUnit comes with several built-in factories that allow shallow rendering or replacing components with test dummies and test stubs. See the Substituting (mocking) component page for details.

Progress Telerik

Premium sponsor: Progress Telerik.

Packt

Editorial support provided by Packt.

.NET Foundation

Supported by the .NET Foundation.