Search code examples
mvvmcross

MVVM Cross null references when unit testing MxvAsyncCommand


We have recently upgraded to MvvMCross 6.2.2 and noticed we had to change to use Mvx.IoCProvider.

We have found that if we are constructing an MvxAsyncCommand in a ViewModel this causes a null reference exception on all unit tests that call this constructor

*

Result StackTrace:  
at MvvmCross.Commands.MvxCommandBase..ctor()
   at MvvmCross.Commands.MvxAsyncCommand..ctor(Func`1 execute, Func`1 canExecute, Boolean allowConcurrentExecutions)
   at App.Mobile.Core.ViewModels.TestViewModel..ctor(IMvxNavigationService navigation, ITestService encService, ILogger logger)
   at App.Mobile.Core.UnitTests.TestViewModelTests.<TestViewModel_Prepare>d__1.MoveNext()

*

Looking at the source in github the problem is due to Mvx.IocProvider being null.

public MvxCommandBase()
    {
        if (!Mvx.IoCProvider.TryResolve<IMvxCommandHelper>(out _commandHelper))
            _commandHelper = new MvxWeakCommandHelper();

        var alwaysOnUIThread = MvxSingletonCache.Instance == null || MvxSingletonCache.Instance.Settings.AlwaysRaiseInpcOnUserInterfaceThread;
        ShouldAlwaysRaiseCECOnUserInterfaceThread = alwaysOnUIThread;
    }

A fix has been implemented in the "develop" branch but this isn't available on nuget.

public MvxCommandBase()
    {
        // fallback on MvxWeakCommandHelper if no IoC has been set up
        if (!Mvx.IoCProvider?.TryResolve(out _commandHelper) ?? true)
            _commandHelper = new MvxWeakCommandHelper();

        // default to true if no Singleton Cache has been set up
        var alwaysOnUIThread = MvxSingletonCache.Instance?.Settings.AlwaysRaiseInpcOnUserInterfaceThread ?? true;
        ShouldAlwaysRaiseCECOnUserInterfaceThread = alwaysOnUIThread;
    }

Does anyone know of a workaround to initialize this IoCProvider within our unit test projects.


Solution

  • As you can see here the IoCProvider is resolved by getting the singleton of IMvxIoCProvider

    public static IMvxIoCProvider IoCProvider => MvxSingleton<IMvxIoCProvider>.Instance;
    

    So all you have to do is to initialize the IMvxIoCProvider. As an example you can use this test, so in order to initialize it, you have to do:

    MvxSingleton.ClearAllSingletons(); // This should be done in the test to clear all references of previous tests if necessary.
    var instance = MvxIoCProvider.Initialize();
    

    HIH