Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does composition root needs unit testing?

I was trying to find an answer but it seems it's not directly discussed a lot. I have a composition root of my application where I create a DI-container and register everything there and then resolve needed top-level classes that gets all dependencies. As this is all happening internally - it becomes hard to unit test the composition root. You can do virtual methods, protected fields and so on, but I am not a big fan of introducing such things just to be able to unit test. There are no big problems with other classes as they all use constructor injection. So the question is - does it make much sense to test the composition root at all? It does have some additional logic, but not much and in most cases any failures there would pop up during application start. Some code that I have:

public void Initialize(/*Some configuration parameters here*/)
    {
        m_Container = new UnityContainer();

        /*Regestering dependencies*/

        m_Distributor = m_Container.Resolve<ISimpleFeedMessageDistributor>();
    }

    public void Start()
    {
        if (m_Distributor == null)
        {
            throw new ApplicationException("Initialize should be called before start");
        }

        m_Distributor.Start();
    }

    public void Close()
    {
        if (m_Distributor != null)
        {
            m_Distributor.Close();
        }
    }
like image 728
Ilya Chernomordik Avatar asked Aug 28 '13 13:08

Ilya Chernomordik


People also ask

What Cannot be unit tested?

Any component that interacts with an external database, files, or the network cannot be checked as part of unit testing. Unit tests primarily test isolated components during the product's early development phase. Developers using frameworks like Nodejs, Angular, etc., employ Unit Testing Frameworks.

What is a composition root?

What is a Composition Root? Definition. A Composition Root is a (preferably) unique location in an application where modules are composed together. Figure 1. Close to the application is entry point, the Composition Root takes care of composing object graphs of loosely coupled classes.

Should everything be unit tested?

The answer to the more general question is yes, you should unit test everything you can. Doing so creates a legacy for later so changes down the road can be done with peace of mind. ... Usually, something which is hard to unit test is also poorly designed. Writing for testability means writing for better design.

Should you unit test dependencies?

Unit tests check on the behavior of units. Think of a class as being a unit. Classes, more often than not, have external dependencies. Tests for such classes should not use its real dependencies because if the dependencies have defects, the tests fail, even though the code inside the class may be perfectly fine.


1 Answers

does it make much sense to test the composition root at all?

Would you like to know whether your application is written correctly? You probably do and that's why you write tests. For this same reason you should test your composition root.

These tests however are specifically targeted at the correctness of the wiring of the system. You don't want to test whether a single class functions correctly, since that's already covered by some unit test. Neither do you want to test whether classes call other classes in the right order, because that's what you want to test in your normal integration tests (call an MVC controller and see whether the call ends up in the database is an example of such integration test).

Here are some things you probably should test:

  • That all top-level classes can be resolved. This prevents you from having to click through all screens in the application to find out whether everything is wired correctly.
  • That components only depend on equally or longer lived services. When components depend on another component that is configured with a shorter lifetime, that component will 'promote' the lifetime of that dependency, which will often lead to bugs that are hard to reproduce and fix. Checking for this kind of issues is important. This type of error is also known as a lifestyle mismatch or captive dependency.
  • That decorators and other interception mechanisms that are crucial for the correctness of the application are applied correctly. Decorators could for instance add cross cutting concerns such as transaction handling, security and caching and it is important that these concerns are executed in the right order (for instance a security check must be performed before querying the cache), but it can be hard to test this using a normal integration test.

To be able to do this however, you will need to have a verifiable DI configuration.

Do note that not everybody shares this opinion though. My experience however is that verifying the correctness of your configuration is highly valuable.

So testing these things can be challenging with some IoC containers, while other IoC container have facilities to help you with this (but Unity unfortunately lacks most of those features).

Some containers even have some sort of verification method that can be called that will verify the configuration. What 'verify' means differs for each library. Simple Injector for instance (I'm the lead dev for Simple Injector) has a Verify method that will simply iterate all registrations and call GetInstance on each of them to ensure every instance can be created. I always advice users you call Verify in their composition root whenever possible. This is not always possible for instance because when the configuration gets big, a call to Verify can cause the application to start too slowly. But still, it's a good starting point and can remove a lot of pain. If it takes to long, you can always move the call to an automated test.

And for Simple Injector, this is just the beginning. Simple Injector contains Diagnostic Services that checks the container on common misconfigurations, such as the earlier stated 'lifestyle mismatch'.

So you should absolutely want to test, but I'm not sure whether to call those tests "unit tests", although I manage to run those tests in isolation (without having to hit a database or web service).

like image 69
Steven Avatar answered Oct 05 '22 23:10

Steven