views:

115

answers:

1

I am trying to implement Dependency Injection to make my app tester friendly. I have a rather basic doubt.

Data layer uses SqlConnection object to connect to a SQL server database. SqlConnection object is a dependency for data access layer. In accordance with the laws of dependency injection, we must not new() dependent objects, but rather accept them through constructor arguments. Not wanting to upset the DI gods, I dutifully create a constructor in my DAL that takes in SqlConnection.

Business layer calls DAL. Business layer must therefore, pass in SqlConnection. Presentation layer calls Business layer. Hence it too, must pass in SqlConnection to business layer.

This is great for class isolation and testability. But didn't we just couple the UI and Business layers to a specific implementation of the data layer which happens to use a relational database?

Why do the Presentation and Business layers need to know that the underlying data store is SQL? What if the app needs to support multiple data sources other than SQL server (such as XML files, Comma delimited files etc.) Furthermore, what if I add another object upon which my data layer is dependent on (say, a second database). Now, I have to modify the upper layers to pass in this new object.

How can I avoid this merry-go-round and reap all the benefits of DI without the pain?

+2  A: 

Frankly what you should do is create a generic interface for accessing your data. A Repository, and then create a Sql Implementation of this interface, and dont inject your SqlConnection.

This way in testing you just replace the SqlImplementation of the common interface with the Testing Implementation (mock) and off you go.

I think you're drilling into the DI too far. In the case of a Sql Implementation you should possibly inject the connection string, but not the SqlConnection itself.

Aren
So, what you are saying is encapsulate whatever settings are needed to connect to a data source into a SqlRepository class that implements an IRepository interface and propagate that down the hierarchy. And embed the knowledge of what repository to select in a controller class at the top of the hierarchy. So, DI is achieved alongwith decoupling, since the intermediate layers don't need to know what specific repository is in use. That would certainly work.
cs31415
Yes, you could then make `TestRepository` or `FlatFileRepository` or `DavidBowieInSpaceRepository` and just select the implementation you want in your config. The details of HOW the IRepository does it's job is irrelevant to your controller/intermediate layers.That way you can also use DI to satisfy the implementation-specific configuration through DI in the constructor.
Aren
Thanks for the clear explanation. I would have voted you up if I had the reputation.
cs31415
Heh, no worries :) Just happy to help.
Aren