Inversion of Control facilitates dependency injection. It is not the same thing. But more on that in just a sec.
Jeffery Palermo has been writing that inversion of control is not about testability. I agree, IoC, is about loosely coupled designs. He then goes on to say there is no such thing as loose coupling, which I wholeheartedly disagree with. The is no such thing as no coupling, but coupling to an interface is far more flexible than being coupled to a concrete type. Hence the term loose. Ok, now that I have stated my opinion. I want to write a bunch stuff to see if I understand IoC, because I see a lot of terms getting overloaded and it confuses me. So...
Here's how I see the world. There is this design principle called the Dependency Inversion Principle which states:
High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.
Wow, what does that mean?! Well, think of a typical layered architecture. What this principle is saying is that the layers in an application should be coupled to interfaces or abstract base classes (interfaces are better), not to each other. That is, the UI Layer should not just "new up" a Service class and use it. Also, I shouldn't write methods in the UI Layer that refer to concrete types in the Service Layer.
If I accept that this is a good thing, how would I build such as system? After all, the UI Layer does, in fact, need something from the Service Layer, which in turn relies on stuff in the Data Access Layer. The answer to this question of course is dependency injection, which simply means that I would pass the Service dependencies that my UI object needed at the time it was created. This is typically done via the constructor. In this way, the UI object would not create any instances directly. It's getting everything it needs through its' constructor.
Ok, sounds good on paper, but how would this be accomplished? It seems that some code would need to exist somewhere (or would it! dun dun duuun!) that would be responsible for creating these dependent objects in the first place. And that code would be tightly coupled to something, maybe some kind of Factory assembly that was responsible for creating everything.
However, there is a better option: Inversion of Control. With IoC, I essentially request the objects that I need instead of declaratively telling the system to create the specific objects I want. That is, I say "Can I please have something that implements IEmployeeService" instead of "Gimme an EmployeeService, fool".
This style of programming is accomplished with an IoC container (personally, I like the Windsor container). The container is configured in some way, either in code or some form of external configuration file. The configuration defines what objects should be returned for what requests (e.g. a request for IEmployeeService should return an EmployeeService3). In this way, you can think of an IoC container as a big bucket o' objects...on pirate ship...floating in a sea of chocolate.
The IoC container automatically creates the objects that are requested. If those objects depend on other objects, which also happen to be configured in the bucket, it will create those, too, and inject them into the requested object.
A side effect of all of this, of course, is testability.