views:

268

answers:

3

I am relatively new to unit testing, and completely new to mocking. I have a database class that wraps the DbProvider factory that I would like to create unit tests for without connecting to the database.

How would I mock the DbProvider factory, so I could pass it in to test my class? Would I also need to mock the DbConnection, DbCommand, etc.? A small sample of my code follows:

public Database(DbProviderFactory dbProviderFactory) {
    Provider = dbProviderFactory;
}

public int UpdateRecords(string sql, CommandType type, params DbParameter[] parameters) {
    int numberOfRecordsUpdated;

    using (var connection = CreateConnection()) {

        // Add ConnectionString
        connection.ConnectionString = ConnectionString;

        // Create command to hold the update statment
        using (var command = CreateCommand()) {
            try {
                command.Connection = connection;
                command.CommandType = type;
                command.CommandText = sql;

                // Add Parameters
                foreach (var parameter in parameters) {
                    command.Parameters.Add(parameter);
                }

                // Open Connection
                connection.Open();

                // Execute SQL
                numberOfRecordsUpdated = command.ExecuteNonQuery();
            } finally {
                command.Parameters.Clear();
            }
        }
    }

    return numberOfRecordsUpdated;
}
A: 

Data access classes are all about integrating with DB. Roy Osherove for example consider this classes an exception when unit testing. I'm interested too on how to test this type of code. +1 for question.

IOW I'm not sure that it's advisable to mock around data access classes.

http://stackoverflow.com/questions/109432/what-not-to-test-when-it-comes-to-unit-testing

Petar Repac
I agree with that, but it sometimes feels that a large percentage of what I do deals with getting data from the database, or performing logic on that. This question goes more to testing the functions that consume this class, allowing me to return a predetermined dataset, and test resulting functionality.
Sean
If you follow SRP principle you would then have separate classes e.g. DataGetter and DataProcessor. DataProcessor is then an ideal candidate for unit testing. You would then make a mock or stub in place of DataGetter and perform operations on DataProcessor. No database would be involved. You must configure mock/stub that fakes DataGetter so that it returs data that simulate real data from DB.For testing DataGetter DB must be involved. It isn't unit test anymore but I'm not aware of other way to test data access classes.
Petar Repac
+1  A: 

Integration Testing


If you are interested (as judging by your comment) in testing getting data from the database you will be performing an integration test.

The difference to unit testing for these types of test are they are run less often - best practice dictates you run these before committing to source control.

The reason being they are slower and you will be hitting a real database (a test database at least). On each run you will need to wipe the database or not commit the changes - you seem to know what you're doing here so I'll leave how you handle this up to yourself.

Mocking


As for testing your logic that uses the database - mocking and dependency injection is the way to go.

I use Moq - its probably the easiest mocking framework to use. It actually isn't just for mock objects (despite the name) and you can produce stubs and fakes with it.

Pseudo mocking goes like this (using a DB example):

  • Set up mock
  • Tell it what to do (expect) - e.g. a call to save.
  • Use your SUT (System Under Test)
  • Verify the mock - in this case that the save method was called within your SUT.

For further help - check Google - there are some good resources out there for unit testing and mocking.

Finglas
A: 

I would personally mock the class that contains the higher level data access functionality (like UpdateRecords etc) and use this mock to return the predetermined datasets.

The use of DbProvider and the corresponding DbCommand etc are an implementation detail of your data access layer and not really relevant to the higher level functionality that uses the returned values.

PlausiblyDamp