bUnit v2 - The Blazor unit testing library vNext

After some time we released the first preview of bUnit v2. This release is a major release with some new features and improvements. In this post, I will highlight some of the most important changes, including new features and some breaking changes.

Overall goal

Version 2 of bUnit is less of a complete new set of API's but more of a refinement of the existing ones. We wanted to make it easier for users to have fine-grained control over their components in their tests. Nevertheless, that also means we have some breaking changes in the APIs. We tried to keep them to a minimum, but some were necessary to achieve the goal. Let's talk about them first (from an API point of view).

Breaking Changes

Here a small overview over the breaking changes in bUnit v2. I will only go over the bigger changes and will link to the documentation that describes all the breaking changes you might encounter.

.NET 8

To remove some switches in the code base and use newer language features. As version 1 is still supported (and supports .NET 8 as well), you can still use v1 as long as you want (or better: as long as we want 😉).

Renamed Fake to Bunit

Some of the services and helpers in v1 were called Fake at the beginning, like FakeNavigationManager. We renamed them to Bunit (i.e. BunitNavigationManager) to make their origin and purpose more obvious.

Renamed TestContext to BunitContext

Unfortunately, TestContext was and is a well-reserved object name in some of the major testing frameworks. Name clashing is never a good idea, and to streamline the naming throughout bit, we called it BunitContext. We kept the "old" TestContext around and give you a deprecation warning, as this is the most used type throughout bUnit.

Render as a unified API call

In v1 you had a lot of different API’s for almost the same thing: RenderComponent, Render, SetParametersAndRender plus their overloads. Nothing of that anymore - with v2 you have Render with a bunch of overloads to make it easier to write and understand tests.

No bunit.core and bunit.web package anymore

Most of you will not be impacted by that change, but in v1 we had the following packages:

  • bunit - A meta package that automatically includes bunit.core and bunit.web
  • bunit.core - The core functionality of bunit without any “web”-specific stuff like AngleSharp. The idea is that either we or a 3rd party could extend this package to have a good baseline. Imagine there is another Blazor (like the former Mobile Bindings) where bunit should run on.
  • bunit.web - The package that targets the “web” deperatment of Blazor. So everything that somewhat outputs HTML. It builts on top of bunit.core and extends many types or introduce new types.
  • bunit.template - Well, that is “just” our template that automatically includes bunit (the metapackage) to your solution.
  • bunit.generators - A set of source code generators to help you out with stubbing.

With v2, we decided to unify core and web into one package and kept it inside the unit package. We checked many 3rd party compoonent libraries whether or not they are using bunit, core or web. In 99% of cases, people are using either bunit.web or “just” bunit. So, we made our lives way simpler by merging them.

Removed the abstraction around bUnits rendered component types.

Our component diagram around rendered output from bUnit looks like this in v1:

Component Diagram

The abstraction was needed, as we had a core and web package. As this is no longer the case, much of the abstraction is gone. In its current state, we only have two types: RenderedFragment and RenderedComponent - and we might even go further and merge them into one type: RenderedComponent. But that is a topic for the future.

A RenderedFragment is the output of render, where you pass in a RenderFragment: Render(@<div>Test</div); - there isn't a component involved. As soon as you specify your component type like Render<Counter>(); we are speaking of a RenderedComponent.

Technically everything is a RenderedComponent for us, as we are wrapping fragments in our own type.

Removed snapshot API

The snapshot API:

var changes = cut.GetChangesSinceFirstRender();

changes.ShouldHaveChanges(...)

Has been completely removed. We saw not much use of it and therefore cut the ties entirely. You can recreate the functionality to some extend with the given OnRender events.

New Features

The new features we are introducing with version 2 of bUnit might be more interesting. So let’s go into them and show their potential use.

Debugger Hints

Another small addition we made was adding some inline tooltips. That should give an overall faster feedback cycle for you while debugging through your stuff. Here are some examples:

The BunitNavigationManager:

Hint 1 RefreshableElementCollection:

Hint 2

And the most important one RenderedFragment and RenderedComponent are returned from Render and RenderComponent:

Hint 3

So as you can see, smaller hints can save you some seconds while debugging your stuff!

BunitContext inherits from IAsyncDisposable

The new old BunitContext inherits from IDisposable and IAsyncDisposable to give you full flexibility and control over the lifetime of your objects. We had reports that this feature is important for some - so we got you covered.


Download, Feedback and Outlook

As we are still in the midst of developing v2 things can change. Also, to get a comprehensive overview of the breaking changes, have a look at our migration guide. You can download the latest previews, like always, via Nuget.

Every Feedback is welcome and important to us. Head over to our issue tracker or discussion board.

While this is the first preview, we are for sure not finished yet. The documentation has to be updated with a more in-depth migration guide. We will keep the old documentation (as well as bunit v1) around for quite some time. Also feature-wise we are not done, there are some points we would like to tackle before the public API surface is stable (and therefore ready for v2).

For example, we are actively investing in those two features:

  • Allowing to await async disposables via DisposeComponentsAsync
  • Allowing to walk up the render tree

Conclusion

Version 2 is not so much of a new feature-rich release, but a major overhaul of the inner workings of bUnit. The main advantage is that we can have a higher cadence of new features in the future and for you a simpler Set of API's that does almost the same (and sometimes more) than the v1 counterpart.

.NET 8 and Blazor United / Server-side rendering

New .NET and new Blazor features. In this blog post, I want to highlight the new features that are hitting us with .NET 8 in the Blazor world. So let's see what's new.

bUnit Generators - Generate your stubs automatically

We made a recent addition to bUnit that we think will make your life easier. We call it bUnit Generators. It's a set of code generators that will help you create stubs for your third-party components.

Tutorial Unit and E2E Testing in Blazor - Part 1

This blog post should give you an easy and good introduction how to unit and end-to-end test your Blazor Application. Furthermore it does not matter if we are running server side or client side aka WebAssembly. The main two libraries we are using is first bUnit for unit-testing and Playwright for end-to-end testing. So let's dive in!

An error has occurred. This application may no longer respond until reloaded. Reload x