Novastorm
Novastorm

Reputation: 1458

Unit testing conundrum: OleDbCommand

One of the classes which I'm trying to unit test makes use of an OleDbConnection object. This object is responsible for returning information held in an MS Access file based on a passed SQL string. The code is:

public void getInformation(DateTime start, DateTime finish)
{
    string getInfo = "";
    string query = "//Query for MS Access goes here";
    transactions = addTransactions(query, conn);
}

Where addTransactions is a private method that returns the list which was retrieved from the database:

private List<string> addTransactions(string query, OleDbConnection conn)
{
    List<string> returnedData = new List<string>();
    OleDbCommand cmd = new OleDbCommand(query, conn);
    try
    {
        if (conn.State == ConnectionState.Closed) conn.Open();
        OleDbDataReader reader = cmd.ExecuteReader();
        while (reader.Read())
        {
            if (!reader.IsDBNull(0))
        }
        returnedData.Add(reader.GetString(0));
    }
    catch (Exception ex)
    {
        Console.WriteLine("OLEB: {0}", ex.Message);
    }
    conn.Close();
    return returnedData;
}

Now I know already from looking at this method that it's going to be difficult to unit test, since the public getInformation() method is void. What I can do is test that the returned data has something in it. My question is how can I write a unit test involving the OleDbConnection?

The only 2 potential solutions I have thought of involve either creating a temp access file (not ideal since we're now outside the scope of unit testing coupled with the potential to fail when the test is run on other developer's machines) or creating a wrapper for OleDbConnection and using that in the unit test (this sounds like the best approach, but I've got no idea where to start on this).

Upvotes: 1

Views: 893

Answers (2)

David
David

Reputation: 218798

or creating a wrapper for OleDbConnection and using that in the unit test

That would be my approach. Objects which aren't directly mockable/testable often represent dependencies in and of themselves. And all dependencies should be provided rather than internally instantiated.

A wrapper can be a simple pass-through which provides the identical functionality. Have it be driven by an interface and code to that interface, so you can provide mocks for that interface for unit testing. (As an added bonus, your mocks give you something to observe even when the method being tested returns void. So you don't have to drill too deep into the system that you're testing, just observe what gets called on the mocks.)

Starting at the aggregate root of what you're mocking, you need to wrap the OleDbConnection. A simple example to get started might look like this:

public interface IDbConnection
{
    IDbCommand CreateCommand();
    // other methods
}

public class MyOleDbConnection : IDbConnection
{
    private OleDbConnection conn;

    public MyOleDbConnection()
    {
        // initialize "conn" here
    }

    public IDbCommand CreateCommand()
    {
        return conn.CreateCommand();
    }

    // other pass-thru methods
}

Essentially it's just a pass-through wrapper for identical functionality exposed by the underlying object(s). The benefit there is that this object doesn't really need to be unit-tested, because it doesn't contain any meaningfully testable logic. (Sure, it would be nice to get to 100%, but the return on investment just isn't there with this class.)

As you can see, this also involves creating a wrapper for OleDbCommand in a similar manner. Again, just pass-through methods.

Once you have your dependencies wrapped and mockable, you'd change your class to use the wrappers. For example, instead of this:

OleDbCommand cmd = new OleDbCommand(query, conn);

Which internally holds a reference to the dependency, you'd do this:

IDbCommand cmd = conn.CreateCommand();

Which asks the dependency for a reference to something. This puts the responsibility of maintaining the dependency on the dependency itself, rather than in this class you're trying to test. (And, in doing so, trying to keep free to dependencies.)

Once the dependencies are fully removed from your class, you're free to mock and test all you like.

Upvotes: 2

Naish O&#39;Loughlin
Naish O&#39;Loughlin

Reputation: 59

Just create an MS file and place in package then always use same file to test that way you can even write the data and know exactly what its returning instead of assuming if any data is returned its correct! Just an idea multiple ways to go about it.

Upvotes: -1

Related Questions