Container self-test

Issue #2 resolved
Britain Crooker created an issue

Would it be possible to create some sort of self-test to sanity check what is registered in the container?

Currently we are not making use of any sort of automatic dependency injection (e.g. via constructors or attributes on fields), instead we are resolving at each point. We want switch from this pattern, but the one advantage the previous patter has is that it allows us to self-test the application to make sure that an implementor of each interace has been linked into the application.

I have been playing with the constructor injection handling and lets say you have a class that has a single constructor with 3 interfaces you expect to be resolved with the owner class. If you forget to register an implementation of one of those interfaces, Spring will resolve the outer class using the base TObject.Create constructor instead. This would be one of the cases where it would be good to have the self-test catch this.

We have a large number of applications with a great deal of shared code so this level of verification comes in very handy to make sure additions to one application didn't destabilize another application because of a lack of component registration.

Perhaps this could be done during .Build (if it is fast) or a separate method if it takes time.

Comments (5)

  1. Stefan Glienke repo owner

    While this sounds appealing at first I agree with Mark Seemann that such test would unfortunately be worthless.

    If I understand it right, currently you are using the service locator pattern. How does that allow you to self-test the application in a way you cannot with dependency injection? If you have some code that resolves IFoo and you did not register TFoo that will result in an exception at exactly that point - at runtime.

    The constructor problem unfortunatly exists because RTTI cannot tell if a method is overloaded or hidden (like the default constructor is hidden if you write some parameterized constructor). To solve this problem you can specify the Inject attribute on the constructor you want to be called and not leave it to the container to find the best match. The container then will use this constructor and complain if any dependency cannot be resolved.

  2. Britain Crooker reporter

    We have wrapped the container with an additional method called "Requires" which is somewhat analogous to RegisterType. Any unit that is calling Resolve on an interface also must call Container.Requires in the initialization section. We use a static analysis script to make sure this is being done. So our continuous build process both runs the analysis script to make sure the Requires calls are in place, and then each EXE runs in a self-test mode to verify that the Requires/Resolve calls match up. This makes sure that are interfaces being resolved (known via Requires) are also registered. If any of the above fails, the build is marked as a failure. This works actually very well for our current setup. However we would like to push the use of the container further towards the app root, leveraging the deep resolving of dependencies. Until we get there, the outer resolution of interfaces would be handled via our current setup (this handles the IQux example in the article you referenced) - we mainly want to verify the existence of dependencies internal to the container.

    The [Inject] attribute on the constructor should help as well.

  3. Stefan Glienke repo owner

    You can actually get all types that are registered in the container. You would need to loop them and then apply some similar logic as the component activators do (looking for the constructor and then checking if the dependencies can be resolved) without actually creating anything.

  4. Log in to comment