1.0.0 - preview 02 - final release before v1
[1.0.0-preview-02] - 2021-03-26
The following sections list all changes in 1.0.0 preview 02.
The plan is to make this the last preview release of bUnit. If no big blocking bugs show up the next two weeks, a non-preview release of bUnit will be pushed out to the world.
Added
List of new features.
-
Added the ability to pass a "fallback
IServiceProvider
" to theTestServiceProvider
, available through theServices
property on aTestContext
. The fallback service provider enables a few interesting scenarios, such as using an alternative IoC container, or automatically generating mocks of services components under test depend on. See the Injecting Services into Components Under Test page for more details on this feature. By @thopdev in #310. -
Added
Task<Expection> ITestRenderer.UnhandledException
property that returns aTask<Exception>
that completes when the renderer captures an unhandled exception from a component under test. If a component is missing exception handling of asynchronous operations, e.g. in theOnInitializedAsync
method, the exception will not break the test, because it happens on another thread. To have a test fail in this scenario, you can await theUnhandledException
property on theTestContext.Renderer
property, e.g.:using var ctx = new TestContext(); var cut = ctx.RenderComponent<ComponentThatThrowsDuringAsyncOperation>(); Task<Exception?> waitTimeout = Task.Delay(500).ContinueWith(_ => Task.FromResult<Exception?>(null)).Unwrap(); Exception? unhandledException = await Task.WhenAny<Exception?>(Renderer.UnhandledException, waitTimeout).Unwrap(); Assert.Null(unhandledException);
In this example, we await any unhandled exceptions from the renderer, or our wait timeout. The
waitTimeout
ensures that we will not wait forever, in case no unhandled exception is thrown.NOTE, a better approach is to use the
WaitForState
orWaitForAssertion
methods, which now also throws unhandled exceptions. Using them, you do not need to set up a wait timeout explicitly. -
Added a simple fake navigation manager, which is registered by default in bUnit's service provider. When the fake navigation manager's
NavigateTo
method is called, it does two things:- Set the
Uri
property to the URI passed to theNavigateTo
method (with the URI normalized to an absolute URI). - Raise the
LocationChanged
event with the URI passed to theNavigateTo
method.
Lets look at an example: To verify that the
<GoesToFooOnInit>
component below calls theNavigationManager.NavigateTo
method with the expected value, do the following:<GoesToFooOnInit>
component:@inject NavigationManager NavMan @code { protected override void OnInitialized() { NavMan.NavigateTo("foo"); } }
Test code:
// Arrange using var ctx = new TestContext(); var navMan = ctx.Services.GetRequiredService<NavigationManager>(); // Act var cut = ctx.RenderComponent<GoesToFooOnInit>(); // Assert Assert.Equal($"{navMan.BaseUri}foo", navMan.Uri);
Since the
foo
input argument is normalized to an absolute URI, we have to do the same normalization in our assertion.The fake navigation manager's
BaseUri
is set tohttp://localhost/
, but it is not recommended to use that URL directly in your code. Instead create an assertion by getting that value from theBaseUri
property, like shown in the example above. - Set the
-
Added additional bUnit JSInterop
Setup
methods, that makes it possible to get complete control of invocation matching for the created handler. By @egil.
Changed
List of changes in existing functionality.
-
WaitForAssertion
andWaitForState
now throws unhandled exception caught by the renderer from a component under test. This can happen if a component is awaiting an asynchronous operation that throws, e.g. a API call using a misconfiguredHttpClient
. By @egil in #310. -
Improvements to error message from bUnit's JSInterop when it receives an invocation that it has not been set up to handle. By @egil in #346.