C# – How to unit test code that uses Dapper

Dapper makes your code difficult to unit test. The problem is that Dapper uses static extension methods, and static methods are difficult to mock out.

One approach is to wrap the Dapper static methods in a class, extract out an interface for that wrapper class, and then dependency inject the wrapper interface. In the unit tests, you can then mock out the wrapper interface.

In this article, I’ll show how to do this approach.

First, the repository code using Dapper

Let’s start by looking at repository code that is using Dapper to execute a query:

public class MovieRepository { private readonly string ConnectionString; public MovieRepository(string connectionString) { ConnectionString = connectionString; } public IEnumerable<Movie> GetMovies() { using(var connection = new SqlConnection(ConnectionString)) { return connection.Query<Movie>("SELECT Name, Description, RuntimeMinutes, Year FROM Movies"); } } }
Code language: C# (cs)

To make this code unit testable, we need to mock out the static connection.Query() method. Right now, this is actually connecting to the database and executing the query.

We can use the technique explained in this article about mocking out static methods:

  • Wrap the static method calls in a class and extract out an interface for the wrapper.
  • Dependency inject the interface into the repository.
  • In the unit tests, mock out the wrapper interface and pass it into the repository.

Wrap the static Dapper method

Create a class and wrap the static Query() method:

using Dapper; public class DapperWrapper : IDapperWrapper { public IEnumerable<T> Query<T>(IDbConnection connection, string sql) { return connection.Query<T>(sql); } }
Code language: C# (cs)

Notice this is not passing in all the optional parameters that the Dapper method uses. This simplifies things a little bit. If you really aren’t using the other parameters, you might as well leave them out of the wrapper class.

Now extract an interface from the wrapper class:

public interface IDapperWrapper { IEnumerable<T> Query<T>(IDbConnection connection, string sql); }
Code language: C# (cs)

Dependency inject the wrapper interface into the repository

Add IDapperWrapper as a constructor parameter in MovieRepository:

private readonly IDapperWrapper DapperWrapper; public MovieRepository(string connectionString, IDapperWrapper dapperWrapper) { ConnectionString = connectionString; DapperWrapper = dapperWrapper; }
Code language: C# (cs)

Write a unit test and mock out the wrapper

The following test verifies that the repository is using DapperWrapper to execute the expected SQL Query with a properly built IDbConnection object:

[TestMethod()] public void GetMoviesTest_ReturnsMoviesFromQueryUsingExpectedSQLQueryAndConnectionString() { //arrange var mockDapper = new Mock<IDapperWrapper>(); var expectedConnectionString = @"Server=SERVERNAME;Database=TESTDB;Integrated Security=true;"; var expectedQuery = "SELECT Name, Description, RuntimeMinutes, Year FROM Movies"; var repo = new MovieRepository(expectedConnectionString, mockDapper.Object); var expectedMovies = new List<Movie>() { new Movie() { Name = "Test" } }; mockDapper.Setup(t => t.Query<Movie>(It.Is<IDbConnection>(db => db.ConnectionString == expectedConnectionString), expectedQuery)) .Returns(expectedMovies); //act var movies = repo.GetMovies(); //assert Assert.AreSame(expectedMovies, movies); }
Code language: C# (cs)

At first this test will fail because the code hasn’t been updated to actually use DapperWrapper, so it’s still trying to actually connect to the database (which times out after 15 seconds and throws an exception).

Ok, let’s update the code to use DapperWrapper:

public IEnumerable<Movie> GetMovies() { using(var connection = new SqlConnection(ConnectionString)) { return DapperWrapper.Query<Movie>(connection, "SELECT Name, Description, RuntimeMinutes, Year FROM Movies"); } }
Code language: C# (cs)

Now the test passes.

Since it’s mocking out Dapper, it’s not really connecting to the database. This makes the test deterministic and fast – two qualities of a good unit test.

Leave a Comment