This question about unit testing best practices mentions designing classes for dependency injection. This got me thinking as to what exactly that might mean.
Having just started working with inversion of control containers I have some ideas on the issue, so let me throw them against the wall and see what sticks.
The way I see it, there are three basic types of dependencies that an object can have.
Also, I should mention that not everything should be DI'ed, if you have a simple bit of functionality that was just convenient to factor out to a throw-away class, it is probably ok to instantiate on the spot. Obviously this is a judgement call; if I found it expedient to write a class such as
class PasswordEqualsVerifier {
public bool Check(string input, string actual) { return input===actual;}
}
I probably wouldn't bother dependency injecting it and would just have an object instantiate it directly inside a using block. The corollary being that if it is worth writing unit tests for, then it is probably worth injecting.
So what do you guys think? Any additional guidelines or contrasting opinions are welcome.
The important thing is to try to code to interfaces and the have your classes accept instances of those interfaces rather than create the instances themselves. You can obviously go crazy with this, but it's a general good practice regardless of unit testing or DI.
For example, if you have a Data Access Object, you might be inclined to write a base for all DAOs like this:
public class BaseDAO
{
public BaseDAO(String connectionURL,
String driverName,
String username, String password)
{
// use them to create a connection via JDBC, e.g.
}
protected Connection getConnection() { return connection; }
}
However, it would be better to remove this from the class in favor of an interface
public interface DatabaseConnection
{
Connection getConnection();
}
public class BaseDAO
{
public BaseDAO(DatabaseConnection dbConnection)
{
this.dbConnection = dbConnection;
}
protected Connection getConnection() { return dbConnection.getConnection(); }
}
Now, you can provide multilple imlementations of DatabaseConnection
. Even ignoring unit testing, if we assume we are using JDBC, there are two ways to get a Connection
: a connection pool from the container, or directly via using the driver. Now, your DAO code isn't coupled to either strategy.
For testing, you can make a MockDatabaseConnection
that connects to some embedded JDBC implementation with canned data to test your code.
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