繁体   English   中英

Ninject内核绑定覆盖

[英]Ninject kernel binding overrides

我只是想知道在内核中重新绑定绑定的最佳做法是什么。

我有一个带有内核的类和一个带有默认生产绑定的私有类模块。

对于测试,我想覆盖这些绑定,以便我可以交换我的Test Doubles / Mocks对象。

MyClass.Kernel.Load(new InlineModule(m=> m.Bind<IDepend>().To<TestDoubleDepend>()))

覆盖IDepend的任何现有绑定?

我尝试尽可能少地在我的代码中直接使用DI内核,而不是依赖于构造函数注入(或选择情况下的Attribute ,例如Attribute类)。 但是,我必须使用抽象层,以便我可以设置DI内核对象,使其在单元测试中可模拟。

例如:

public interface IDependencyResolver : IDisposable
{
    T GetImplementationOf<T>();
}

public static class DependencyResolver
{
    private static IDependencyResolver s_resolver;

    public static T GetImplementationOf<T>()
    {
        return s_resolver.GetImplementationOf<T>();
    }

    public static void RegisterResolver( IDependencyResolver resolver )
    {
        s_resolver = resolver;
    }

    public static void DisposeResolver()
    {
        s_resolver.Dispose();
    }
}

使用这样的模式,您可以通过使用模拟或伪实现调用RegisterResolver来设置单元测试中的IDependencyResolver ,该实现返回您想要的任何对象,而无需连接完整模块。 如果您将来选择切换到另一个容器,它还具有从特定IoC容器中抽象代码的第二个好处。

当然,您还需要根据需要向IDependencyResolver添加其他方法,我只是将这里的基础知识作为示例。 是的,这将要求您在Ninject内核周围编写一个超级简单的包装器,它也实现了IDependencyResolver

你想要这样做的原因是你的单元测试应该只测试一件事,并且通过使用你的实际IoC容器,你实际上比一个被测试的类更多地运动,这可能导致错误的负面因素,使你的测试脆弱和(更重要的是)随着时间推移开发人员对其准确性的信心。 这可能导致测试冷漠和放弃,因为测试失败但软件仍然可以正常工作(“不用担心,一个总是失败,这不是什么大不了的事”)。

我只是希望这样的事情有效

        var kernel = new StandardKernel(new ProductionModule(config));
        kernel.Rebind<ITimer>().To<TimerImpl>().InSingletonScope();

ProductionModule是我的生产绑定,我通过在特定测试用例中调用Rebind来覆盖。 我在重新绑定的几件物品上打电话重新绑定。

优点:如果有人向生产模块添加了新的绑定,我会继承它们,因此它不会以这种方式破坏,这可能很好。 这一切都适用于Java中的Guice ...希望它也可以在这里工作。

我倾向于做一个单独的测试项目完成它自己的绑定 - 我当然假设我们正在谈论某种单元测试。 测试项目使用自己的内核并将测试项目中的模块加载到该内核中。 项目中的测试在CI构建期间执行,并通过构建脚本执行完整构建,但测试从未部署到生产中。

我意识到你的项目/解决方案设置可能不允许这种组织,但从我看到的看起来似乎很典型。

Peter Mayer的方法对于单元测试很有用,但恕我直言,使用构造函数/属性注入手动注入Mock是不是更容易?

在我看来,对测试项目使用特定绑定对于其他类型的测试(集成,功能)更有用,但即使在这种情况下,您肯定需要根据测试更改绑定。

我的方法是某种kronhrbaugh和Hamish Smith的混合,创建了一个“依赖解析器”,你可以注册和注销要使用的模块。

我会向MyClass添加一个接受模块的构造函数。
这不会用于生产,但会用于测试。
在测试代​​码中,我将传递一个模块,该模块定义了所需的测试双精度数。

对于我正在进行的项目,我为每个环境(测试,开发,阶段,生产等)创建了单独的模块。 这些模块定义了绑定。

因为dev,stage和production都使用了许多相同的绑定,所以我创建了一个共同的模块。 然后每个人都添加环境特定的绑定。

我还有一个KernelFactory,当传递一个环境令牌时,它将使用适当的模块对一个IKernel进行假脱机。

这允许我切换我的环境令牌,这反过来会自动更改我的所有绑定。

但是如果这是用于单元测试的话,我同意上面的评论,即允许手动绑定的简单构造函数是一种方法,因为它使Ninject远离你的测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM