【问题标题】:How to mock Prisms IContainerRegistry如何模拟棱镜 IContainerRegistry
【发布时间】:2018-10-18 16:04:17
【问题描述】:
  • Prism.Ninject 7.1.0.431
  • 棱镜 7.1.0.431
  • NUnit 3.3.3
  • N替换

在使用 Prism 6.3 之前,我们进行了一组单元测试,以确认我们的所有绑定都已到位,如下所示

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}" );
    }
}

但是在 Ninject 7.1 中,IModule 接口发生了一些变化,所以现在部件的注册方式有所不同

public void RegisterTypes(
        IContainerRegistry containerRegistry )

我只是想用这种新的 IModule 格式重新启动和运行我的单元测试。我曾尝试将我的给定更改为如下

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

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

    SUT = new MyModule();
}

但是,当我尝试运行测试时,我得到了以下结果。

System.InvalidCastException:无法将“Castle.Proxies.IContainerRegistryProxy”类型的对象转换为“Prism.Ioc.IContainerExtension`1[Ninject.IKernel]”类型。

如果有人知道我可以如何模拟它,我将不胜感激,因为我目前处于僵局。

【问题讨论】:

  • 为什么不能使用真正的实现?您不会为 Prism 的其他组件编写测试,是吗?所以你相信它们能正常工作,就像你相信 NSubstitute 一样,它们应该可以在测试中使用。尤其是在这种情况下,我们谈论的是薄包装。

标签: wpf ninject prism prism-7


【解决方案1】:

你应该如何测试一直是一个充满分歧的热门话题,所以我会在这里尝试给你一些一般性的信息。 Prism.Ninject 使用Prism.Ninject.Ioc.NinjectContainerExtension 实现容器抽象。这有两个构造函数,一个是默认构造函数,另一个是允许您传入特定内核的构造函数。

Prism 还为每个容器实现扩展方法,以从抽象中提取容器。您可以通过以下几种方式实现此目的:

containerRegistry.GetContainer().SomeContainerSpecificApi()

或者你可以这样做:

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

同样,您可以通过多种方式实施测试,我不打算讨论您应该如何测试。但是,我会说,如果您不想创建应用程序并且您只是想验证您的类型是否已注册为 Prism 模块,您可以尝试以下操作:

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

【讨论】:

  • 太好了,非常感谢。我改用了 containerExtension.Instance.GetBindings,但结果几乎相同。如果您对如何完成此测试有任何合理的反对意见,请告诉我(只要不是通常的“你错了,我是对的”或“那很愚蠢”,我经常在这里看到代替答案) 如果有更好的方法做某事,我宁愿知道。
  • 我个人对 Ninject API 并不太熟悉。我会说,在我看来,您已经使用 GetBindings 实现了单元测试的目标,这对 IMO 来说非常重要。我要告诉您的唯一要考虑的是,您将从 DryIoc 获得更好的性能……它无疑是我们发布的性能最快的容器。
  • 哦,我同意,几年前我们才开始做 DI,当时一些承包商介绍了它,当时他们最熟悉的是 Ninject,所以我们采用了它。我们过去曾考虑过切换,但我们有一个相当大的代码库需要转移。至少使用 Prism 中的新格式,有朝一日它可能会使传输变得更容易。
【解决方案2】:

我想我已经想通了(或至少取得了进展)

我不得不使用以下内容,而不是用 IContainerRegistry 代替

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

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

    SUT = new MyModule();
}

虽然看起来我将不得不做更多的替代品等,以便让 containerRegistry.Register(等)在我的 TestKernel 中结束以进行验证。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 2012-01-04
    • 2012-01-05
    • 2018-10-25
    • 2021-09-07
    • 2019-01-25
    相关资源
    最近更新 更多