Part one of this series of articles discussed a set of dependency injection frameworks that we will be examining, and also the motivation behind this.
This article describes the tests we will be performing and how they will be constructed in code.
The Scenarios Tested
The following dependency injection scenarios will be tested:
- Configuration and retrieval of an object with (only) string dependencies.
- Injection of an object into an instance of a class.
- Injection of a different object into an instance of the same class as used in test 2.
- Creation of an object with singleton scope (same object retrieved from the container every time requested).
- Creation of an object with prototype or transient scope (different (new) object retrieved from the container every time requested).
- Use of a factory class and method to create a dependent object.
- Injection of the container itself (so it can be used to retrieve objects).
This seems like a reasonable selection of basic and more advanced DI scenarios to me.
I have decided not to look at AOP (aspect-oriented programming) in these frameworks, or other features such as event brokers; I want to purely focus on dependency injection. I also won’t test how hierarchies of containers might work.
Having decided to test the dependency injection scenarios described above I needed a simple example to base the tests on. The logical place to start seemed to be MovieLister from the original Martin Fowler article on dependency injection. Whilst this is not a realistic example most developers are familiar with it, and the scenarios I’m testing are not particularly realistic (in isolation) either. As mentioned, most people are familiar with MovieLister, but I briefly recap it below.
Summary of MovieLister
The idea is that you have one generic MovieLister class that has one key method with signature
public Movie moviesDirectedBy(String director)
This will return all movies directed by the passed-in director. The universe of all movies that these are selected from is provided by another class, which implements the MovieFinder interface. This universe of movies can be different under different circumstances, so an instance of the MovieFinder is dependency injected into MovieLister. The MovieFinder interface has one method as below:
The MovieLister will call this method to get the list of all movies, and then filter for the ones directed by the passed-in director.
As mentioned above, more extensive details on this example can be found in Martin Fowler’s article.
Applying MovieLister to the Test Scenarios
Clearly MovieLister in its basic form does not test all the scenarios that we want to test as outlined above.
How MovieLister will be used for these scenarios is described below. The links are to listings of the actual code for the relevant classes in both Java and .Net. Working code will be posted in future articles in this series.
1. Configuration and retrieval of an object with (only) string dependencies
Obviously there is a Movie class underlying MovieLister (.Net version). For the purposes of these tests this just has title and director string properties, which can be set by setters or by a constructor, and a ToString override that outputs the title and director of the current movie.
The first of our tests simply uses the Movie class. We configure an instance that has a specific title and director using constructor injection, and then retrieve that from our DI container and output the result of calling ToString on it.
2. Injection of an object into an instance of a class.
We create a SimpleMovieFinder class that returns a hard-coded list of movies from the findAll method (.Net version). We then inject that into a MovieLister class (.Net version), and call the moviesDirectedBy method from the MovieFinder interface ( .Net version). This retrieves a list of movies that we iterate over and display with ToString.
3. Injection of a different object into an instance of the same class as used in test 2.
We create a ColonDelimitedMovieFinder class (.Net version). This loads the contents of a colon-delimited file, Movies.txt, and returns the movies in that in its findAll method. We inject an instance of this into an instance of the same MovieLister class as in 1., and output the results in the same way.
Surprisingly, many of the frameworks struggled with this test, although it seems pretty basic to me. In fact the Guice team have given a name to the ‘problem’ of injecting different objects into a class in different circumstances: the ‘robot legs problem’.
4. Creation of an object with singleton scope (same object retrieved from the container every time requested).
Rather than create a new object for this we simply make the MovieLister from test 2 into a singleton. Then for the test we request it from the DI container a second time. We need some way of identifying whether it’s the same object, and to do this we assign every instance of MovieLister an ID via a static method in the class. In this test the IDs of the two objects should be the same (since they are the same object).
5. Creation of an object with prototype or transient scope (different (new) object retrieved from the container every time requested).
Again we reuse code from an earlier test. In this case we make the MovieLister from test 3 have transient scope, and to test it we request it from the DI container a second time. We then look at the version IDs of the two objects as above: in this case they should be different.
6. Use of a factory class and method to create a dependent object.
For this we set up a ComplexMovieFinder class (.Net version). As you can see this is a very simple class that just returns a list of movies it has been given from its findAll method. The complexity comes in how the list of movies is constructed and handed to this class. This class will be instantiated, and have its list of movies handed to it, by the ComplexMovieListerFactory class. This class varies in implementation depending on the framework used: see section 7 below.
7. Injection of the container itself (so it can be used to retrieve objects).
We combine this with test 6 above: the ComplexMovieListerFactory class will have the container injected into it and will retrieve all objects of type Movie from it. It will then create the ComplexMovieFinder class and give it this list of movies.
Unlike the other classes shown in this article, the code for the ComplexMovieListerFactory varies greatly depending on the DI framework. In fact this test cannot be performed in all frameworks.
We will look at the code for it in the Spring Java framework in the next article in this series.
This article outlined the tests we will be performing on our various DI frameworks. Part 3 of this series of articles shows these tests implemented in the Spring Java framework. This includes the code for the factory class described immediately above, the XML configuration for the container, and the code to execute the tests.