In my profiler reports I'm increasingly seeing the results of mock-based testing with dependency injection. Many of the dependencies were static, but because we want to test methods in isolation they are changed to instance members, like the following example:
class ShortLivedThing {
IDependency1 dep1;
IDependency1 dep2;
IDependency1 dep3;
...
int TheRealData;
// Constructor used in production
public ShortLivedThing() {
dep1 = new Dep1(); dep2 = new Dep2(); dep3 = new Dep3();
}
// DI for testing
public ShortLivedThing(IDependency1 d1, IDependency2 d2, IDependency3 d3) {
dep1 = d1(); dep2 = d2(); dep3 = d3();
}
}
In turn the dependencies most of the time have other dependencies and so on. This results in the instantiation of a tree of (mostly "static") objects every time a method call is done outside of tests. Each of the objects are very small (just a few pointers), but the tree effect turns this into an ever increasing performance hit.
What can we do about it?
It seems to me like you need to leverage the features a proper dependency injection framework can give you. Do not use different construction logic for testing/production.
With spring, singleton injections are only performed at container startup. Prototype injections are done every time. The full wiring is also done each time you run a unit test, if it's being wired. So profiling unit tests is generally not a good idea.
Maybe you're using too little of the singleton scopes and too much prototype scope ? (Prototype = new instance every time)
The nice thing about spring injection is that you can use scope proxies, meaning your object graph can look like this:
A Singleton
|
B Singleton
|
C Prototype (per-invocation)
|
D Singleton
|
E Session scope (web app)
|
F Singleton
And each request would only create 1 instance of C and one instance of E per session. A, B, D and F are singletons. If it's not a webapp you dont have session scope by default, but you can also make custom scopes (a "Window" scope sounds cool for a windowed desktop app). The clue here is that you can "introduce" scopes at any level, effectively you can have ten layers of singleton objects and all of a sudden something session scoped shows up. (This can really revolutionize how you implement some cross-cutting features in a layered architecture but that's a different story)
This really gives the minimum object creation possible within a DI model, I think.
Although this is Spring for Java I believe a number of other DI frameworks should support similar features. Maybe not the most minimalistic ones.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With