wpfninjectprismprism-7

How to mock Prisms IContainerRegistry


Previously using Prism 6.3 we had a set of unit test to confirm that we had all of our bindings in place as follows

protected IKernel TestKernel;

[SetUp]
public void Given
{
    TestKernel = new StandardKernel();
    SUT = new MyModule( TestKernel );

    Core = Assembly.Load( "MyDLL.Core" ).GetTypes();
    Common = Assembly.Load( "MyDLL.Common" ).GetTypes();

    SUT.Initialize();
}

[ Test ]
public void Then_ViewModels_Will_Be_Bound()
{
    var testCollection = Common
        .Where( item => item.IsPublic )
        .Where( item => item.Name.EndsWith( "ViewModel" ) );

    foreach ( var item in testCollection )
    {
        Assert.That( TestKernel.GetBindings( item ).Any, $"Test Failed:  {item.Name}" );
    }
}

However in Ninject 7.1, the IModule interface has changed somewhat, so now parts are registered differently in

public void RegisterTypes(
        IContainerRegistry containerRegistry )

I'm just trying to get my unit tests up and running again with this new IModule format. I had tried changing my given to be as follows

protected override void Given()
{
    TestKernel = new StandardKernel();

    TestContainerRegistry = Substitute.For<IContainerRegistry>();
    TestContainerRegistry.GetContainer().Returns( TestKernel );

    SUT = new MyModule();
}

However I get the following when I attempt to run my tests.

System.InvalidCastException : Unable to cast object of type 'Castle.Proxies.IContainerRegistryProxy' to type 'Prism.Ioc.IContainerExtension`1[Ninject.IKernel]'.

If anyone has any idea how I might be able to mock this it would be appreciated, as I'm currently at an impasse.


Solution

  • How you should test is always a hot topic full of disagreement, so I will try to give you some general information here. Prism.Ninject implements the container abstractions with the Prism.Ninject.Ioc.NinjectContainerExtension. This has two constructors, a default and one that allows you to pass in a specific Kernel.

    Prism also implements extension methods for each of the containers to pull the container from the abstraction. You can achieve this in a couple of ways:

    containerRegistry.GetContainer().SomeContainerSpecificApi()
    

    Alternatively you could do:

    var app = new MyApp();
    app.Container.GetContainer().SomeContainerSpecificApi();
    

    Again there are a variety of ways that you could implement your tests and I'm not about to get into how you should test. I will however say that in the event you don't want to create an app and you're just looking to validate that your types are registered for a Prism Module you might try something like:

    var containerExtension = new NinjectContainerExtension();
    var module = new MyModule();
    module.RegisterTypes(containerExtension);
    Assert.IsTrue(containerExtension.Instance.IsRegistered<MyType>());