One Java programming "best practice" that has been strongly reinforced for me during the last several weeks is making sure you have a declared interface that defines the behavior (signature) of your Dao (data access objects) classes.
Using the Java programming language as an example, what I am specifically saying is that if you have a Dao object that uses JDBC behind the scenes to access a database (DB2, SQL Server, MySQL, Oracle, whatever) named something like As400Dao
, you should also declare an interface named something like As400DataSource
, and your As400Dao
should then implement that interface.
If you're not familiar with this concept, hopefully right now you're asking "Why?"
Programming best practices - A Mock Dao object for testing
The answer is simple: If you want to create unit tests to test your code, having an Interface that defines the signature of your Dao also lets you create a "mock" Dao object that you can use in your tests.
Let's look at how this works with a real but simple example.
// the interface public interface As400DataSource { /** * Return the price of a product in pennies. */ public int getPrice(String productName); } // the class you'll use in production public class As400Dao implements As400DataSource { public int getPrice(String productName) { // put your real sql code here ... String sql = "SELECT price FROM products WHERE product_name =?"; // i'm not going to implement it all, but you get the idea } } // the class you'll use in your unit tests public class MockAs400Dao implements As400DataSource { public int getPrice(String productName) { // this is a "mock" version of the getPrice method if (productName.equals("pizza")) return 1000; if (productName.equals("soft drink")) return 100; } }
Your production code
The next important thing for you to do is to make sure you reference the As400DataSource
interface in your code. In your production code you'll have some code like this that really hits the database:
As400DataSource as400 = new As400Dao(); int price = as400.getPrice("pizza"); // do something in your production code with the price
In that code the object I'm creating is really an As400Dao
object, but as far as my as400
reference is concerned, it's a As400DataSource
.
Your unit test code
But in your unit tests you'll create an instance of the MockAs400Dao
instead, like this:
As400DataSource as400 = new MockAs400Dao(); int price = as400.getPrice("pizza"); // do something with the price in your test code, like maybe building // an Order object: Order order = new Order(); order.addItem("pizza", price); // then later on you'll have some form of assertion, like this: Assert.equals(1000, order.getTotal());
In this code the object I'm creating is really an MockAs400Dao
object, but again, as far as my as400
reference is concerned, it's a As400DataSource
.
That's a key concept behind this entire approach: your actual objects (the things on the right side of the equal sign) can be any class that implements the As400DataSource
interface, but the reference you create on the left side of the equal sign (the as400
reference) is defined only as being a As400DataSource
, which is really an interface.
Now you're programming to the interface, and not worrying about the actual implementation(!).
Programming best practices - Create interfaces for your Dao classes
It's hard to write a great example without really diving into this topic, but I hope this "programming best practice" example demonstrates why having the As400DataSource
interface is so important. By simply having this interface defined -- and then using it in your code -- you can write real unit tests that don't have to hit the database to properly test your code.
There are a lot of other good reasons for creating interfaces for your classes, but I think it's especially important to do this for your Dao
objects. As you can see, this interface-driven approach can be a great help when it comes time to testing.