Tech Valley Code Camp

This past weekend saw the inaugural gathering of the Tech Valley Code Camp in Albany, NY. For their first conference attendance was quite acceptable. I had the honor of conducting two conference sessions, Introduction to Unit Testing, and Introduction to TDD. Clearly by the titles it’s evident these sessions were exciting and action packed! Well as Mom told me, ya got to eat your veggies before you get desert. As it turns out the folks that attended the sessions were engaged and definitely interested in the topic of unit testing.

As an example of what should and should not be tested I built a small demo application using Win Forms, ADO.Net, and the MVP pattern. My purpose in using the MVP pattern was to illustrate how forms are inherently difficult to test. While this example demonstrated greater testability and adherence to the guideline of never testing the database, an explanation of how the MVP pattern worked absorbed more time then I anticipated. So as a review I thought I would reiterate here the process of refactoring an untestable piece of ADO.Net code to make it testable.

The application has an MVP triad for viewing stock items; the components of the triad include a StockItemPresenter, an IStockItemPresenter interface, an IStockItemCallbacks interface, an IStockItemView interface, and a StockItemView user control. In answer to the question, “What the heck! What’s with all the interfaces?” the implementation of my MVP demo is based on the Separated Interface design pattern. Briefly this allows me to have my presenters in one project, views in another, and no circular references between the two. A brief description of each component follows:

  • StockItemPresenter – concrete implementation of the IStockItemPresenter and IstockItemCallbacks residing in the Presenters project; all logic with regards to accessing and processing of stock items is performed within this class.
  • IStockItemPresenter – the contract provided to the User Interface project that allows instantiation and access to the StockItemPresenter’s logic.
  • IStockItemCallbacks – the contract provided to the view that allows communication of user actions back to the presenter.
  • IStockItemView – the contract provided to the presenter by which data is supplied to the view.
  • StockItemView – a user control inheriting from IStockItemView known as the “view” where data is displayed and users can initiate action.

Here is the scenario: My presenter implements the public method GetData() exposed by the IStockItemPresenter, with the following code.

public void GetData()
{
string connectionString = ConfigurationManager.ConnectionStrings[“Demo1”].ConnectionString;
string selectString = “Select * from Demo.StockItem”;
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(selectString, connection);
SQLDataAdapter result = new SqlDataAdapter(command);

StockItems items = new StockItems();
items.EnforceConstraints = false;adapter.Fill(items);

_view.StockItems = items;
}

This code is perfectly legal and is very commonly used when dealing with ADO objects in a Data Access Layer. So, what you may ask, makes this code untestable? It is an issue of control with the method’s collaborators. Here the method has control and is creating local variables that can not be alter from outside the method. When any unit test is run against this method the collaborators will act in their normal manner and attempt to connect through the SqlConnection and SQLDataAdapter directly to the database. That violates the guideline of never testing the database, which is an entirely different topic.

So, what can be done to make this code testable and better at the same time? What we need to be able to do is control the methods collaborators from outside of the method. Once the method’s collaborators can be controlled, they can be replaced with a fake. The faked collaborator can take the form of a stub or a mock, the complexity of the type will determine which to use. For the purpose of this discussion we will use a mock. A mock is a dynamic representation or proxy of an object, not the actual object itself. Interfaces are good candidates for mocking, but this code doesn’t contain any. As it turns out though, the SQLDataAdapter implements the IDataAdapter interface. That means if the method can be changed to use an IDataAdapter, and if we can control the instance of the IDataAdapter, then we can provide the method a fake. So, let’s refactor the code to use the IDataAdapter interface:

public class StockItemPresenter : IStockItemPresenter, IStockItemCallbacks
{

private IDataAdapterFactory _adapterFactory;
private IStockItemView _view;

public StockItemPresenter(IDataAdapterFactory adapterFactory)
{
_adapterfactory = adapterFactory;
}

public void GetData()
{
IDataAdapter adapter = _adapterFactory.GetAdapter(selectString);

StockItems items = new StockItems();
items.EnforceConstraints = false;
adapter.Fill(items);

_view.StockItems = items;
}
}

Several points about this refactoring need to be explained. The first is that we have now introduced a new object called an IDataAdapterFactory. The responsibility of this object to provide an abstraction of the creation of SQLDataAdapters. Using the Dependency Injection pattern we can feed the IDataAdapterFactory into the presenter when it is instantiated. This approach allows the mocking of the IDataAdapterFactory in the unit test and injecting the mock into the presenter. The next point is the inclusion of the IDataAdapter in the GetData() method. Under normal usage a true SQLDataAdapter would be returned by the IDataAdapterFactory, but in our unit test the factory can be instructed to return a mocked IDataAdapter, thereby allowing the unit test to make a call against the adapter adapter.Fill(items) without involving the database.

As a result of this simple refactoring our code is now fully testable, and arguably simpler. By inverting control of the GetData() method’s collaborators the unit test can fully validate the behavior of the method without reaching beyond it’s boundaries. We also removed redundancy from the codebase as all usage of SQL types are located in the adapter factory. And, in my estimation, the GetData() method more readable and intent revealing.

The demo application is available at UnitTest-1.ZIP. The zip file contains the demo application, a backup of the database, and a copy of my presentation slides. In the sample code I demonstrate the before and after code and how to perform the mocking with Rhino mocks. I hope this clears up some of the questions that were left in the presentation.

Advertisements
Explore posts in the same categories: Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: