Great post! We also worked with dependency injection to achieve better decomposition of tests. While you suggest to change the application, we took the approach of changing the testing framework. We separate unit under test construction from the test logic! But I think both approaches can work together very nice. Let me give an example:
@Test public Kitchen testKitchen() { ... create some kitchen and test it... return kitchen; }
@Test @Depends("testKitchen") public House testHouse(Kitchen kitchen) { ... use the kitchen to create a house and test it... return house; }
We extended JUnit with explicit depedencies (@Depends) and use return values and parameters to inject the result of one test into the next test. If a prerequisite fails, all dependees are skipped.
We call our approach "Example Driven", because (other than eg mocks) our objects are actually real example instances of the unit under test. And each test method is an example of how to use it.
@fuzzyman: Javascript too supports gorilla (nee guerilla) patching.
IMHO Dependency Injection sets my code up for better design as I am freed to use interfaces more throughout my code.
I prefer dependency injection to gorilla patching as I'm freed to declare behavior inside the testing class (where I want it) instead of creating a bogus unit that mocks something else.
I disagree, what you are suggesting that "ask for what you need" is not DI but rather Registry doesn't seem right. The registry patten seems to be basically a global object which allows you to retrieve what you want. DI is the concept of an object saying I need all these dependencies to work correctly, and whoever creates the object provides them.
The registry pattern is a global object where you put in whatever you might ever need, and then look them up. THe total antithesis to DI, because it not only makes everything stored in some static context, it also makes life miserable for testing because to test, you then have to setup the registry with your mock instead of the original and let it get it. Nastiness....
The Registry object doesn't have to be one global object, actually you could have different registries for different dependencies. You also don't need a static context. I think you may be thinking implementations like JNDI, that are not good at all, but these are problems with the implementation and not the pattern. A problem in the Registry pattern is that someone will have to instantiate the Registry and add dependencies to it.
Anyway, yes, the Registry is the antithesis of Dependency Injection and that's what I've tried to explain in my last comment.
When you say that an object asks for its dependencies you imply that it asks *something* for those. In Dependency injection you won't ask anyone, you just declare your dependencies to whoever is interested in those (via constructor signature or metadata) and assume that those will be fulfilled when you need them.
If you ask something you will have to ask what has your dependencies. The role of Registry is exactly to hold dependencies so clients can ask or them.
So, my conclusion is that if you ask for your dependencies you are often using Registry (as you have to ask somebody). If you declare your dependencies and assume they'll be there when you need you use Dependency Injection.
ah I see what you are getting at. Well, with the ask approach, I believe what he basically means is that the constructor just says that I need this, and it is up to who ever is using that class to provide it. You can go one step higher and plug in a framework which provides all of these, or you might have to, in your main class, construct the object graph creating all the base and calling these constructors which ask for these things.
So in that way, it moves away from a registry pattern. True you can use a registry pattern to satisfy this as well, but it allows you to inject mocks and ignore objects which you don't care about.
Of course, you could just use Guice or Spring which allows easy dependency injection and managing dependencies which create your object graph, and why wouldn't you ? It makes life so much easier :D
Hm.. I don't know, I think our problem -or my disagreement- is in the semantic of "ask". I don't have any problems with the examples presented here, they *do* represent Dependency Injection for me.
The only point I disagree in this article is this sentence:
"Asking for your dependencies instead of constructing them withing the application logic is called 'Dependency Injection' and is nothing new in the unit-testing world.".
As I said DI (and the example provided in this post) is not about asking anything, it is about declaring your dependencies.
The House featured in this text won't ask for a Kitchen, it just declares that it needs one. Asking for a kitchen would be something like:
And that's not what happens. With or without a proper framework like guice or Spring or Pico the House in the example just declares what it needs, it won't ask for a dependency or create their own objects.
Most of the points you make in your "dynamic languages are not more testable" seem to be based on a misunderstanding of the testing techniques used in dynamic languages.
Patching global state is dangerous - but can easily be localised to within the body of a single test method (e.g. by a decorator in Python). You are right that it makes parallelising tests harder - personally I prefer to parallelise tests across several machines though (or use multiple isolated interpreters to parallelise which also avoids the 'global' problem).
More to the point, mutating global state (class level attributes) is only one small technique - more importantly you can patch *instance* methods without touching the class at all, and can trivially use mocks without having to jump through hoops (duck typing rather than static typing).
Dynamic languages are *significantly* easier to test - for many reasons.
I really don't get this. Why can't I just have a 'new' command in the House's constructor? That's what the constructor is for in my understanding of object oriented design.
In my test environment I then just swap out the Kitchen and put in a Mock Kitchen:
House myHouse = new House(); myHouse.kitchen = new Mock();
.. I may be completely wrong, I'm a noob to unit testing.
The benefit of dependency injection becomes obvious if the Kitchen is really expensive to instantiate, and especially if it is not strictly needed for all your tests of House. In fact, it should not be needed at all and should be tested in a separate test fixture. The collaboration between classes are integration tests and should not be part of unit tests.
Another scenario would be if you have a dependency that communicates with a slow data source (e.g. a remote database). You would rather inject a mocked database provider. This would also benefit from using interfaces to separate interface from implementation, which is not covered in this article.
Wow great tip; i have to learn about unit testing for my summer practice and this is an excellent starting point!
ReplyDeleteGreat post! We also worked with dependency injection to achieve better decomposition of tests. While you suggest to change the application, we took the approach of changing the testing framework. We separate unit under test construction from the test logic! But I think both approaches can work together very nice. Let me give an example:
ReplyDelete@Test
public Kitchen testKitchen() {
... create some kitchen and test it...
return kitchen;
}
@Test
@Depends("testKitchen")
public House testHouse(Kitchen kitchen) {
... use the kitchen to create a house and test it...
return house;
}
We extended JUnit with explicit depedencies (@Depends) and use return values and parameters to inject the result of one test into the next test. If a prerequisite fails, all dependees are skipped.
We call our approach "Example Driven", because (other than eg mocks) our objects are actually real example instances of the unit under test. And each test method is an example of how to use it.
More see JExample
cheers,
AA
Ah, but you just don't have this problem with Python. Dynamic languages (in general) are *so* much easier to test.
ReplyDelete"In this updated version of House it is not possible to instantiate House without the Kitchen."
In Python this statement is simply not true.
You patch the name 'Kitchen' at the module level, and house will use the patched Kitchen rather than the original.
@fuzzyman: Javascript too supports gorilla (nee guerilla) patching.
ReplyDeleteIMHO Dependency Injection sets my code up for better design as I am freed to use interfaces more throughout my code.
I prefer dependency injection to gorilla patching as I'm freed to declare behavior inside the testing class (where I want it) instead of creating a bogus unit that mocks something else.
@Josh
ReplyDeleteWe (Resolver Systems) use a combination of both - although we probably do a bit too much mocking in unit tests.
I often find that dependency injection just adds *another* layer that also needs to be tested though.
@fuzzyman
ReplyDeleteYeah, I'm pretty familiar with mocking too much (both in the context of testing and regular life) ;)
I'm a Java guy so I'm using Spring for all of my injection needs (which is pretty well tested).
Layers are great so long as they add flexibility and don't get in your way.
This should become the holy grail for testing. +42 for dependency injection.
ReplyDeleteLanguages with powerful meta programming -often dynamic languages but not necessarily- surely ease the pain but some caution is needed:
ReplyDeletehttp://fragmental.tw/2008/01/08/please-do-not-break-into/
--
About Depency Injection, it is not about "asking for your dependencies instead of creating them". That's is the Registry pattern:
http://martinfowler.com/eaaCatalog/registry.html
Dependency Injection *is about having all dependencies automagically fulfilled by something* -often a container.
cheers
I disagree, what you are suggesting that "ask for what you need" is not DI but rather Registry doesn't seem right. The registry patten seems to be basically a global object which allows you to retrieve what you want. DI is the concept of an object saying I need all these dependencies to work correctly, and whoever creates the object provides them.
ReplyDeleteThe registry pattern is a global object where you put in whatever you might ever need, and then look them up. THe total antithesis to DI, because it not only makes everything stored in some static context, it also makes life miserable for testing because to test, you then have to setup the registry with your mock instead of the original and let it get it. Nastiness....
Hi,
ReplyDeleteThe Registry object doesn't have to be one global object, actually you could have different registries for different dependencies. You also don't need a static context. I think you may be thinking implementations like JNDI, that are not good at all, but these are problems with the implementation and not the pattern. A problem in the Registry pattern is that someone will have to instantiate the Registry and add dependencies to it.
Anyway, yes, the Registry is the antithesis of Dependency Injection and that's what I've tried to explain in my last comment.
When you say that an object asks for its dependencies you imply that it asks *something* for those. In Dependency injection you won't ask anyone, you just declare your dependencies to whoever is interested in those (via constructor signature or metadata) and assume that those will be fulfilled when you need them.
If you ask something you will have to ask what has your dependencies. The role of Registry is exactly to hold dependencies so clients can ask or them.
So, my conclusion is that if you ask for your dependencies you are often using Registry (as you have to ask somebody). If you declare your dependencies and assume they'll be there when you need you use Dependency Injection.
cheers
ah I see what you are getting at. Well, with the ask approach, I believe what he basically means is that the constructor just says that I need this, and it is up to who ever is using that class to provide it. You can go one step higher and plug in a framework which provides all of these, or you might have to, in your main class, construct the object graph creating all the base and calling these constructors which ask for these things.
ReplyDeleteSo in that way, it moves away from a registry pattern. True you can use a registry pattern to satisfy this as well, but it allows you to inject mocks and ignore objects which you don't care about.
Of course, you could just use Guice or Spring which allows easy dependency injection and managing dependencies which create your object graph, and why wouldn't you ? It makes life so much easier :D
Hm.. I don't know, I think our problem -or my disagreement- is in the semantic of "ask". I don't have any problems with the examples presented here, they *do* represent Dependency Injection for me.
ReplyDeleteThe only point I disagree in this article is this sentence:
"Asking for your dependencies instead of constructing them withing the application logic is called 'Dependency Injection' and is nothing new in the unit-testing world.".
As I said DI (and the example provided in this post) is not about asking anything, it is about declaring your dependencies.
The House featured in this text won't ask for a Kitchen, it just declares that it needs one. Asking for a kitchen would be something like:
class House {
private final Kitchen kitchen;
public House(Kitchen kitchen) {
this.kitchen = somethingThatHasKitchens.getKitchen();
}
//...
}
And that's not what happens. With or without a proper framework like guice or Spring or Pico the House in the example just declares what it needs, it won't ask for a dependency or create their own objects.
cheers
For people who think that this article does not apply to dynamic languages (as some of you pointed out in the comments) I would like to point to: http://www.testabilityexplorer.org/blog/2008/07/13/dynamic-languages-are-not-more-testable
ReplyDelete@Misko
ReplyDeleteMost of the points you make in your "dynamic languages are not more testable" seem to be based on a misunderstanding of the testing techniques used in dynamic languages.
Patching global state is dangerous - but can easily be localised to within the body of a single test method (e.g. by a decorator in Python). You are right that it makes parallelising tests harder - personally I prefer to parallelise tests across several machines though (or use multiple isolated interpreters to parallelise which also avoids the 'global' problem).
More to the point, mutating global state (class level attributes) is only one small technique - more importantly you can patch *instance* methods without touching the class at all, and can trivially use mocks without having to jump through hoops (duck typing rather than static typing).
Dynamic languages are *significantly* easier to test - for many reasons.
I really don't get this. Why can't I just have a 'new' command in the House's constructor? That's what the constructor is for in my understanding of object oriented design.
ReplyDeleteIn my test environment I then just swap out the Kitchen and put in a Mock Kitchen:
House myHouse = new House();
myHouse.kitchen = new Mock();
.. I may be completely wrong, I'm a noob to unit testing.
The benefit of dependency injection becomes obvious if the Kitchen is really expensive to instantiate, and especially if it is not strictly needed for all your tests of House. In fact, it should not be needed at all and should be tested in a separate test fixture. The collaboration between classes are integration tests and should not be part of unit tests.
DeleteAnother scenario would be if you have a dependency that communicates with a slow data source (e.g. a remote database). You would rather inject a mocked database provider. This would also benefit from using interfaces to separate interface from implementation, which is not covered in this article.
Loved the article. Doesn't say anything about how you should test the Factory class though...
ReplyDelete