gpt4 book ai didi

c# - 安全地对IoC/DI配置进行广泛的更改

转载 作者:行者123 更新时间:2023-11-28 20:27:43 26 4
gpt4 key购买 nike

具体问题:
如何在我的代码库中对DI配置进行单元测试,以确保在对自动绑定检测进行一些更改后,所有连接仍能正常进行。



我一直在为使用Ninject进行Ioc / DI的小型代码库(也许约10页?和20-30个服务/控制器)做出贡献。

我发现在Ninject内核中它被配置为BindDefaultInterface。这意味着,如果您要求它提供IFoo,它将去寻找Foo类。

但这是基于字符串模式,而不是C#继承。这意味着MyFoo : IFoo将不会绑定,您还可能获得其他奇怪的“巧合”绑定,也许吗?

到目前为止,这一切都可行,因为每个人碰巧都调用了自己的WhateverService接口IWhateverService

但这对我来说似乎非常脆弱且不直观。当我想将我的实时FilePathProvider : IFilePathProvider重命名为AppSettingsBasedFilePathProvider(而不是Test中使用的RootFolderFilePathProviderNCrunchFilePathProvider)时,它特别断了,它告诉你它做了什么: )

有两种替代配置:


BindToDefaultInterfaces(请注意复数形式)会将MyOtherBar绑定到IMyOtherBarIOtherBarIBar(我认为)
如果每个类都完全实现1个接口,则BindToSingleInterface有效。
BindToAllInterfaces确实听起来像。


我想更改为那些,但是我担心会引入一些难以理解的错误,从而某些地方的类以应有的方式停止绑定,但是我没有注意到。

有没有办法以合理的安全性来测试此更改/进行更改(无论如何,不​​仅仅是“做到并希望”!),而不仅仅是尝试锻炼每个可能的组件。

最佳答案

所以,我设法解决了这个问题...
我的解决方案并非没有缺点,但从根本上实现了我想要的安全性。


摘要

大致来说有两个方面:


以编程方式测试DI内核知道的每个绑定都可以干净地解析。
以编程方式测试代码库中使用的每个相关接口都可以完全解析。


两者都采用大致相同的路径:


重构您的DI配置代码,以便它的定义应用程序内容绑定的核心部分可以与其余启动代码隔离地运行。
在测试开始时,请调用上面的DI配置代码,以便您拥有站点使用的内核对象的副本,可以测试其绑定
执行一定数量的反射,以生成内核应能够提供的相关Type对象的列表。
(可选)过滤该列表,以忽略一些您不需要测试的类和接口(例如,您的代码无需担心内核是否知道如何自举,因此它可以忽略任何绑定)它在属于您的DI框架的名称空间中。)。
然后,循环遍历剩下的接口类型对象,并确保kernel.Get(interfaceType)的每个对象都没有异常运行。


继续阅读以获取更多Gory详细信息...



验证所有定义的内核绑定

这将是特定于所讨论的DI框架的,但是对于Ninject来说,这是一件很麻烦的事情...

如果Ninject内核具有内置的方法来公开其绑定集合,那就更好了,但是事实并非如此。但是bindings集合是私有可用的,因此,如果您执行正确的Reflection咒语,就可以掌握它们。然后,您必须执行更多的反射操作才能将其绑定对象转换为{InterfaceType : ConcreteType}对。

我将发布关于如何分别从Ninject提取这些对象的细节,因为这与通常如何为DI config设置测试的问题正交。 {#占位符以链接到该#}

其他DI框架可以通过更公开地提供这些集合(甚至直接提供某种Validate()方法)来简化此过程。

一旦有了内核认为可以绑定的接口列表,就可以遍历它们并测试解决每个接口。

具体细节因语言和测试框架而异,但我使用C#FluentAssertions,因此我分配了Action resolutionAction = (() => testKernel.Get(interfaceType))并声明了resolutionAction.ShouldNotThrow()或类似的内容。


验证代码库中的所有相关接口

上半年一切都很好,但是它告诉您的是,您直接提取的绑定是定义明确的。它不会告诉您是否完全缺少任何绑定。

您可以通过收集代码库中所有有趣的程序集来解决这种情况:

Assembly.GetAssembly(typeof(Main.SampleClassFromMainAssembly))
Assembly.GetAssembly(typeof(Repos.SampleRepoClass))
Assembly.GetAssembly(typeof(Web.SampleController))
Assembly.GetAssembly(typeof(Other.SampleClassFromAnotherSeparateAssemblyInUse))


然后,对于每个 Assembly反映其类,以查找其公开的公共接口,并确保每个接口都可以被内核解析。

这种方法存在两个问题:


如果您错过了一个Assembly,或者有人添加了一个新的Assembly但没有将其添加到测试中怎么办?


这不是直接的问题,但这意味着您的测试无法像您所想的那样保护您。我进行了安全网测试,断言Ninject内核知道的每个程序集都应包含在要测试的程序集列表中。如果有人添加了一个新的程序集,则它可能包含内核提供的某些内容,因此此安全网测试将失败,从而使开发人员注意此测试类。


内核没有提供的类呢?


我发现主要由于明显的原因未提供这些类-也许它们实际上是由Factory类提供的,或者该类使用不佳且是手动构造的。无论哪种方式,这些类都是少数,可以相对轻松地列为显式异常(“遍历所有类;如果classname = foo,则忽略它。”)。


总体来说,这有点毛。而且更脆弱,我通常希望进行测试。

但这有效。

可能是您在进行更改之前编写的内容,仅仅是为了使您可以在更改之前运行一次,在更改之后运行一次,以检查是否有任何损坏,然后将其删除?

关于c# - 安全地对IoC/DI配置进行广泛的更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47835373/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com