Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq and SqlConnection?

I'm writing unit tests for one of our products and have been used Moq to successfully mock connections to Entity Framework. However, I've come across the following method:

public static productValue findValues(string productName, string dbConnectionString)
{
    try
    {
        SqlConnection conn = new SqlConnection(dbConnectionString);
        conn.Open();
        //Do stuff 
    }
}

Which accesses our database inside that method using a passed connection string. Is it possible to setup a mock DB using Moq and create a connection string which points to the mocked DB? I've trying doing something along the lines of

var mockSqlConnnection = new Mock<SqlConnection>();

Though I'm unsure if this is the correct approach, as this would mock the connection itself rather than the DB.

like image 835
Novastorm Avatar asked Jan 22 '16 10:01

Novastorm


2 Answers

I had a similar problem.

I introduced an SqlDataContext wrapper around the SqlConnection which inherited from and ISqlDataContext interface:

class SqlDataContext : ISqlDataContext {

    private readonly SqlConnection _connection;

    public SqlDataContext(string connectionString)
    {
        _connection = CreateConnection(connectionString);
    }

    public IDataReader ExecuteReader(string storedProcedureName, ICollection<SqlParameter> parameters)
    {
       // execute the command here using the _connection private field.
       // This is where your conn.Open() and "do stuff" happens.
    }

    private SqlConnection CreateConnection(string connectionString)
    {
        if (string.IsNullOrEmpty(connectionString))
        {
            throw new ArgumentNullException("connectionString");
        }

        return new SqlConnection(connectionString);
    }
}

interface ISqlDataContext
{
    IDataReader ExecuteReader(string storedProcedureName, ICollection<SqlParameter> parameters);
}

You can add overloads to the ISqlDataContext as you need.

What this means is that you can then mock the ISqlDataContext as requires using Moq or similar and return mock values.

Means you can then test your repository or anything else that hits the database through the SqlConnection without actually having to hit the database.

The other advantage is that you can inject ISqlContext with DI / IoC as needed.

like image 101
Graham Avatar answered Sep 16 '22 20:09

Graham


late but why not with mstest:

[TestMethod]
MyTestWithInternSqlConnection()
{
   using (ShimsContext.Create())
   {
      // simulate a connection
      ShimSqlConnection.AllInstances.Open = connection => { };
      string commandText;

      // shim-Mock all called methods
      ShimSqlCommand.AllInstances.ExecuteReader = command =>
      {
         commandText = command.CommandText;
         return new ShimSqlDataReader();
      };

      int readCount = 0;
      ShimSqlDataReader.AllInstances.Read = reader => readCount == 0;
      ShimSqlDataReader.AllInstances.GetSqlStringInt32 = (reader, i) =>
      {
         readCount++;
         return "testServer";
      };

      var theReadedString = AMethodUnderTestThatReadsFromDatabaseAString();
      Assert.IsTrue(theReadedString == "testServer");
   }
}

you need to add a reference to System.Data and then add a Fake for it.

https://msdn.microsoft.com/en-us/library/hh549175.aspx Better is it, if you change the implementation and you can change the used read layer but ...

like image 21
tire0011 Avatar answered Sep 18 '22 20:09

tire0011