I have been following Jacob's series of posts from the beginning, and I agree with most of what he has said. I myself am fairly new to unit testing and I have been using DI just to enable mock objects to test. Being a newcomer, I of course start to wonder if it is worth making design decisions that I otherwise would not have made just to enable testing. If there will never be another implementation of a given object, is it worth creating an interface, injecting the dependency and adding additional complexity and technical debt for the sake of unit tests? This makes TypeMock.Net very attractive.
That being said, I first implemented DI in a project before I ever started unit testing. The requirements called for a framework whose underlying data sources will be changed in future releases and will come in heterogeneous formats. I chose to use DI so that other developers who use the framework would be shielded from the future changes that we had requirements for. Almost one year later, I am very happy with that decision. DI was a great tool to use, and the key point is that it was driven from actual requirements, not "Just in case."
"For example, is Dependency Injection really necessary when you can write tests against your code without it? Does good design necessarily involve DI? More specifically, do you need DI all over the place, or just in specific places where you know dependencies could be a problem? (I'd recommend viewing this video BTW)"
This is a key point, there is no doubt IoC and the related loose coupling can be useful. As with everything else though if you overuse it you get klunky designs. Ultimately in many cases you don't need to be able to replace every part of your system and sometimes using the concrete class directly is just fine.
As an example I'm happy to remove the dependency on the e-mail gateway (and use Ioc/Service Locator and an interface) but I won't change all my references to rules in the domain so that they are injected. The first gives me meaningful decoupling and fast tests and I believe it does improve the design, the second one leaves me cold unless it is driven by a requirement.
It’s funny but I learned about the Dependency-Inversion Principle from Uncle Bob’s book before knowing anything about testing. Later on I managed connect the dots DI + Interfaces + Mocks + easy to test with the principle of DIP and went happy to bed thinking that’s a wrap.
I know nothing about TypeMock but the little I’ve played with DI has given me the feeling that I’m following a good OO practice beyond unit testing.
I've responded to the point of this posting on mockobjects.com but, in the meantime, I could do without this sort of comment.
What do you do if you've spent all this time convincing the powers that be that DI is absolutely essential and now . . . it isn't? That's going to hurt. Much better to just dismiss TypeMock as "too powerful" and move on.
I think DI is relevent outside of unit testing. I refactored a class today using DI for reasons that had nothing to do with testing.
I had a friend start to work on the code with me who wanted to change how a class was loading some data into a child object. The child object had been being getting loaded in a constructor. We refactored so that it would be passed in as an interface instead, as that was the cleanest way to let us each prime the child object the way we wanted to without needlessly impacting other code.
Sure it will make things more testable, but I see that as a positive side effect.
"It’s funny but I learned about the Dependency-Inversion Principle from Uncle Bob’s book before knowing anything about testing. Later on I managed connect the dots DI + Interfaces + Mocks + easy to test with the principle of DIP and went happy to bed thinking that’s a wrap."
Same, but like anything else it can be taken too far. To me some coupling isn't a problem, as long as the coupling isn't too strong and isn't on things that you are worred about.
I keep using this sort of example, but if my domain class is calling out to a DAO/repository then extract an interface and use DI/Service Locator. I wouldn't do the same if my domain class wanted to use a domain rule.