bUnit icon indicating copy to clipboard operation
bUnit copied to clipboard

FakeNavigationManager can't be used in non-render scenarios

Open robertmclaws opened this issue 3 years ago • 2 comments

Describe the Bug

My company ships a product called Breakdance, which is a unit testing framework that (among other things) integrates with Microsoft IHost model to let you do cleaner unit testing that involves Dependency Injection.

We also ship a product called BlazorEssentials, which (among other things) provides a robust MVVM framework for Blazor WebAssembly.

We recently updated our Breakdance.Blazor library to be a FailoverServiceProvider for our BUnitTestContext. In doing so, we discovered the FakeNavigationManager is a more fully-featured service than our TestableNavigationManager, so we removed our version.

The problem now is that we can't test our ViewModels anymore without moving all of our code to execute inside a BUnitTestContext, because your NavigationManager requires a renderer to function.

Expected Behavior:

I would expect to be able to inject a NavigationManager in non-render scenarios.

Requested Fix:

We would like you to please create a new, blank constructor that does not throw an ArgumentNullException on the lack of renderer, and adjust the code so that it doesn't fail if a renderer is not present.

Version info:

  • bUnit version: Latest
  • .NET Runtime and Blazor version: 6.x
  • OS type and version: Windows 11

robertmclaws avatar Aug 30 '22 23:08 robertmclaws

Hi @robertmclaws,

Admittedly we never considered users would use our FakeNavigationManager without a TestContext. If I understand your request correctly, you want all the functionality, but only perform the raise the NotifyLocationChanged event inside the renderers dispatcher if one is available. Otherwise just do it without?

egil avatar Aug 31 '22 10:08 egil

Hey @robertmclaws maybe a bit of background to understand why this renderer.Dispatcher.InvokeAsync is needed in the first place. Just imagine you have a component which does something on the LocationChanged event. And imagine some user changes UI content like a label or what not. Now in your production code you don't have any problem, because there is only one thread. But the whole situation changes when we are in a test: Without the Dispatcher.InvokeAsync the function which is attached to theLocationChanged-event would get triggered from the test-thread and not the blazor thread, which will lead to an exception. Well that is very inconvenient for the user. The user could do something like that:

// The button would trigger a LocationChanged event
cut.InvokeAsync(() => cut.Find("button").Click());

But that is very noisy and technical. So to "catch" that problem, we just route your events through the dispatcher on our own.

linkdotnet avatar Sep 19 '22 17:09 linkdotnet

I would close this bug as "works as intended". It is the way we are using the NavigationManager, which is not intended to be used without a TestContext (mainly because it is a helper for your Blazor components). Almost every functionality is under the TestContext umbrella in some way or another.

That said using a lot of the bUnit objects outside the TestContext or Blazor environment will not work at all. So yes, we could not invoke the Dispatcher if it is null, but I am not sure if this is a common-enough use cases.

linkdotnet avatar Nov 02 '22 10:11 linkdotnet