# Three ways to handle third-party components when writing bUnit tests

Writing trustworthy and reliable tests for your Blazor components can be hard. Especially if you’re heavy relaying on third-party components. In this short blog post I want to provide three ways to handle third-party components when writing bUnit tests. I assume you already know bUnit. If not, please check out their docs at [https://bunit.dev/](https://bunit.dev/).

For all demo code in this project, I’m using [xUnit](https://xunit.net) as testing framework and [MudBlazor](https://mudblazor.com/) as example third-party component library. Though, every option is also viable with other libraries. Lets dive straight into the first option!

# Option 1 - Loading the third-party components

Within our bUnit tests, we can actually load in our third-party components as we normally would within our Blazor application.

```csharp
public CheckoutCartTests()
{
    // We need to add these so we can use MudBlazor components correctly
    Services.AddMudServices();
    JSInterop.Mode = JSRuntimeMode.Loose;
}
```

As you can see, we add the default MudBlazor services and we then set the mode of the JSInterop to loose. The JSInterop is provided by bUnit and makes it possible to mock responses from JS. This is necessary because bUnit does not run any JS. By default the mode is set to `Strict` which will throw an exception if any JS is invoked that is not mocked. By setting it to `Loose` we tell it to just ignore any calls to the JS and return the default value if a JS method is called.

This option will work, though it might have some serious downsides. To illustrate I’ve provided a short list below.

| ✅ Upsides | ❌ Downsides |
| --- | --- |
| Easy and fast to setup | Can make tests brittle because they can become depended on the third-party library if not careful |
| Requires minimal mocking | Won’t really work if the third-party components are heavily depended on JS. We should then mock every method call, though this makes the tests brittle |
| Most production-like test | Makes it hard to really unit test because we’re loading more than just the unit |

Personally I’m not a big fan of this option because of the downsides. Though, I get it when people use it. I would recommend using this option only if the other options are to hard to implement our if you want a production-like test. Though, if you want a production-like test, I would recommend something like PlayWright for end-to-end tests.

# Option 2 - Mocking the third-party components

Instead of fully loading in all the third-party components, bUnit offers a great way to mock these components by using the build in `ComponentFactories`.The `ComponentFactories` contains a method called `AddStub` which accepts different parameters. We can for example stub or what I like to call mock all components from the MudBlazor namespace like this:

```csharp
ComponentFactories.AddStub(type => type.Namespace?.StartsWith("MudBlazor") == true);
```

When you add this line, all components within the MudBlazor namespace will be stubbed. Per default this will mean it will just render nothing. It will only create empty components of the type `Stub<componentType>`.

This is great because now our test is not reliant on the third-party components, though it also has a issue. If we use the line above, no third-party components will be rendered including their child content. Personally I use MudBlazor a lot, which offers things like `MudGrid` and `MudContainer`. These components help me build a layout fast but their child content often is my own code which I would like to test. So to actually do this, we can add specific stubs for each component we like to stub different.

```csharp
ComponentFactories.AddStub(type => type.Namespace?.StartsWith("MudBlazor") == true);

// Stub MudBlazor components but preserve their child content
ComponentFactories.AddStub<MudContainer>(parameters => 
    @<div class="mud-container-stub">@parameters.Get(x => x.ChildContent)</div>);

ComponentFactories.AddStub<MudGrid>(parameters => 
    @<div class="mud-grid-stub">@parameters.Get(x => x.ChildContent)</div>);
```

The code above will actually fix our issue because this will stub all MudBlazor components, but for the `MudContainer` and the `MudGrid` it will actually load in a `div` element with it’s child content. This works because the `ComponentsFactories` works on a last-added order, meaning the latest added stub is checked first.

| ✅ Upsides | ❌ Downsides |
| --- | --- |
| Resilient tests because their is no dependency on the third-party library | Setup can be quite cumbersome if a lot of third-party components need specific stubbing |
| Gives fine-grained control on how third-party components are rendered | Can make the component behave very different than production because it doesn’t load the third-party components the same way |
| Great for specific testing of your own components logic |  |

# Option 3 - Shallow rendering

The final option Shallow rendering is actually quite similar to option 2. Though the big difference is we invert our if statement like this:

```csharp
ComponentFactories.AddStub(type => type != typeof(ComponentTypeWeWantToTest));
```

What this code does, it actually stubs everything that is not the same type of the component you’re trying to test. This will result nothing being rendered except the component itself. This is a great way if you just want to test some logic of the component itself and do not care about any child components.

| ✅ Upsides | ❌ Downsides |
| --- | --- |
| Resilient tests because their is no dependency on other components | Can give issues if your component is heavily reliant on child components |
| Easy and fast to setup | Can make the component behave very different than production because it doesn’t load any other components |
| Great for specific testing of your own components logic |  |

# Conclusion

To summarize, there are three main ways I personally like to test my Blazor components. When writing unit tests for them, I highly recommend option 3 if possible and if there are a lot of dependencies to child components I would recommend option 2. Option 1 is my personal least favorite because of the dependency that is created within your test, which can make the test very brittle.

In this post we quickly went over three ways to handle third party components. Make sure to check out the official documentation at [https://bunit.dev/](https://bunit.dev/) for a more detailed overview of the features bUnit and the `ComponentFactories` have to offer.

If you got any cool additions or questions, feel free to reach out. I would love to hear how you all test your Blazor applications.

For now, happy coding!
