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
andbunit.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
:
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
:
RefreshableElementCollection
:
And the most important one RenderedFragment
and RenderedComponent
are returned from Render
and RenderComponent
:
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.
- You can either go directly to the preview version on NuGet: https://www.nuget.org/packages/bunit/2.0.22-preview (there might be a newer preview version - this was the latest while I was writing the article)
- Or head to our repository: https://github.com/bUnit-dev/bUnit
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.