这是一个很好的方法来测试Ninject绑定? [英] Which is a good approach to test Ninject bindings?

查看:166
本文介绍了这是一个很好的方法来测试Ninject绑定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在我们所有的项目中使用ninject,并作为你就会知道,有时变得难以测试,如果内核就能够解决所有类型的执行时,因为有时控制丢失时绑定和autobindings的幅度(通过ninject扩展)为高。



所以,我问这里有什么我怎么能知道我的内核,装载所有的模块和绑定后,将能够解决所有类型的?你做任何形式的单元测试?或者你只是使应用程序的测试验收,在执行时?任何建议将是巨大的:)


解决方案

写一个集成测试,通过在应用程序遍历所有的根类型测试容器的配置从容器/内核要求它们。通过从容器要求他们,你是确保容器能够集结完整的对象图你。



一个根类型是直接从容器中请求的类型。大多数类型不会是根类型,但对象图的一部分(因为你应该很少在应用程序中调用放回容器)。当你测试根类型的创作,你会立即测试根类型的所有依存关系的建立,除非有代理,工厂或其他机制可能会耽误施工过程。但是,这种拖延施工过程中的机制,做点其他的根对象。你应该找出他们,并测试他们的创作。



从具有为每一根型容器调用一场盛大的测试防止自己。相反,加载(如果可能)使用反射,并在它们之间迭代所有根类型。通过使用某种约定优于配置的方法,你不必1.更改测试每个新根类型保存自己,并且2.防止不完整的测试,当你忘记添加一个测试为新的根类型。



下面是ASP.NET MVC你的根目录类型的控制器的例子:



<预类=郎-CS prettyprint-覆盖> [TestMethod的]
公共无效CompositionRoot_IntegrationTest()
{
//安排
CompositionRoot.Bootstrap();

VAR mvcAssembly = typeof运算(HomeController中).Assembly;从类型

变种controllerTypes =
在mvcAssembly.GetExportedTypes()
,其中的typeof(一个IController).IsAssignableFrom(类型)
,其中!type.IsAbstract
其中,type.IsGenericTypeDefinition
其中type.Name.EndsWith(控制器)
选择的类型!;

//法案
的foreach(在controllerTypes VAR controllerType)
{
CompositionRoot.GetInstance(controllerType);
}
}



更新



塞巴斯蒂安·韦伯做了一个有趣的评论,而我想作出回应。




有关推迟是什么使用支持(Func键)容器或b $ b容器生成$工厂(如城堡的类型化厂设施)创建对象?
你不会用那种测试的抓住他们。这将使你的安全的
假的感觉。




我的建议是有关验证所有的根类型。即在延迟方式创建服务,其实根类型和因此应该明确地测试。这并不当然强迫你密切监控更改配置,并添加一个测试,当你发现一个新的根类型添加不能用,你已经到位约定优于配置的测试进行测试。这是不坏,因为没有人说,使用DI和DI容器意味着我们可以让不小心突然。这需要纪律,以创造良好的软件,无论你用DI与否。



当然,这种做法将变得非常不方便,当你有很多注册那些延迟创作。在这种情况下,有可能出错了您的应用程序的设计,因为使用延迟创作应该是例外,而不是常态。这可能给你带来麻烦的另一件事是,当你的容器,您可以解决未注册的 Func键< T> 登记,将其映射到()= > container.GetInstance< T>()委托。这听起来不错,但是这迫使你把眼光局限在容器登记去找根类型,并使其更容易漏掉一个。由于延迟创作的使用应该是例外,你有明确的登记更好。



另外请注意,即使你无法测试配置的100%,这并不意味着,这使得测试配置是无用的。我们不能自动测试我们的软件的100%,并应考虑我们的软件/配置的那部分不能自动测试的特殊护理。例如你可以不可测部件添加到手动测试脚本,并用手测试。当然,你越是手工测试,更可以(会)出问题,所以你应该尽量让你的配置的可测试性(如你应该所有软件一样)。你当然会得到安全的错觉,当你不知道你的测试,但同样,这适用于在我们的职业的一切。


We use ninject in all our projects, and as you will know, sometimes it becomes hard to test if the kernel would be able to resolve every type at execution time, because sometimes control gets lost when the magnitude of bindings and autobindings (through ninject extensions) is high.

So, what I'm asking here is how can I know that my kernel, after loading all modules and bindings, will be able to resolve every type ? Do you do any kind of Unit Test? Or you just make acceptation tests of the application, at execution time? Any suggestion will be great :)

解决方案

Write an integration test that tests the container's configuration by looping over all root types in the application and requesting them from the container/kernel. By requesting them from the container, you are sure that the container can build-up the complete object graph for you.

A root type is a type that is requested directly from the container. Most types won't be root types, but part of the object graph (since you should rarely call back into the container from within the application). When you test the creation of a root type, you will immediately test the creation of all dependencies of that root type, unless there are proxies, factories, or other mechanisms that might delay the construction process. Mechanisms that delay the construction process however, do point to other root objects. You should identify them and test their creation.

Prevent yourself from having one enormous test with a call to the container for each root type. Instead, load (if possible) all root types using reflection and iterate over them. By using some sort of convention over configuration approach, you save yourself from having to 1. change the test for each new root type, and 2. prevent an incomplete test when you forgot to add a test for a new root type.

Here is an example for ASP.NET MVC where your root types are controllers:

[TestMethod]
public void CompositionRoot_IntegrationTest()
{
    // Arrange
    CompositionRoot.Bootstrap();

    var mvcAssembly = typeof(HomeController).Assembly;

    var controllerTypes =
        from type in mvcAssembly.GetExportedTypes()
        where typeof(IController).IsAssignableFrom(type)
        where !type.IsAbstract
        where !type.IsGenericTypeDefinition
        where type.Name.EndsWith("Controller")
        select type;

    // Act
    foreach (var controllerType in controllerTypes)
    {
        CompositionRoot.GetInstance(controllerType);
    }
}

UPDATE

Sebastian Weber made an interesting comment to which I like to respond.

What about delayed object creation using container backed (Func) or container generated factories (like Castle's Typed Factory Facility)? You won't catch them with that kind of test. That would give you a false feeling of security.

My advice is about verifying all root types. Services that are created in a delayed fashion are in fact root types and they should therefore be tested explicitly. This does of course force you to monitor changes to your configuration closely, and add a test when you detect a new root type is added that can't be tested using the convention-over-configuration tests that you already have in place. This isn't bad, since nobody said that using DI and a DI container means that we may get careless all of a sudden. It takes discipline to create good software, whether you use DI or not.

Of course this approach will get pretty inconvenient when you have many registrations that do delayed creation. In that case there is probably something wrong with the design of your application, since the use of delayed creation should be the exception, not the norm. Another thing that might get you in trouble is when your container allows you to resolve unregistered Func<T> registrations, by mapping them to a () => container.GetInstance<T>() delegate. This sounds nice, but this forces you to look beyond the container registration to go look for root types, and makes it much easier to miss one. Since usage of delayed creation should be the exception, you're better off with explicit registration.

Also note that even if you can't test 100% of your configuration, this doesn't mean that this makes testing the configuration is useless. We can't automatically test 100% of our software and should take special care of that part of our software/configuration that can't be tested automatically. You can for instance add untestable parts to a manual test script, and test them by hand. Of course, the more you have to test by hand, the more can (and will) go wrong, so you should try to maximize the testability of your configuration (as you should do with all of your software). You will of course get a false sense of security when you don't know what your testing, but again, this holds for everything in our profession.

这篇关于这是一个很好的方法来测试Ninject绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆