Creating mock database connections

When working with Entity Framework in a test-driven manner, we need to be able to slip a layer between our last line of code and the framework. This allows us to simulate the database connection without actually hitting the database.

Getting ready

We will be using NuGet Package Manager to install the Entity Framework 4.1 assemblies.

The package installer can be found at http://www.nuget.org/.

We will also be using a database for connecting to the data, and updating it.

Open the Mocking the Database solution in the included source code examples.

Execute the database setup script from the code samples included with this recipe. This can be found in the DataAccess project within the Database folder.

How to do it...

  1. In the BusinessLogic project, add a new C# interface named IDbContext using the following code:
    using System.Linq;
    namespace BusinessLogic
    {
      public interface IDbContext
      {
        IQueryable<T> Find<T>() where T : class;
      }
    }
  2. Add a new unit test in the Test project to test so we can supply false results from a fake database with the following code:
    using System.Collections.Generic;
    using System.Linq;
    using BusinessLogic;
    using DataAccess;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Rhino.Mocks;
    namespace Test
    {
      [TestClass]
      public class QueryTest
      {
        [TestMethod]
        public void ShouldFilterDataProperly()
        {
          //Arrange
          IDbContext mockContext = MockRepository.GenerateMock<IDbContext>();
          mockContext.Expect(x => x.Find<Blog>()).Return(new List<Blog>()
          {
            new Blog(){Id = 1,Title = "Title"},
            new Blog(){Id=2,Title = "no"}
          }.AsQueryable());
          //Act
          var items = mockContext.Find<Blog>().ToList();
          //Assert
          Assert.AreEqual(2,items.Count());
          Assert.AreEqual("Title",items[0].Title);
          Assert.AreEqual("no",items[1].Title);
        }
      }
    }
  3. In the DataAccess project, create a new C# class named BlogContext with the following code:
    using System.Data.Entity;
    using BusinessLogic;
    namespace DataAccess
    {
      public class BlogContext : DbContext, IDbContext
      {
        public BlogContext(string connectionString) : base(connectionString)
        {
        }
        public DbSet<Blog> Blogs { get; set; }
        public IQueryable<T> Find<T>() where T : class
        {
          return this.Set<T>();
        }
      }
    }
  4. In the BusinessLogic project, add a new C# interface called IDbContext with the following code:
    using System.Linq;
    namespace BusinessLogic
    {
      public interface IDbContext
      {
        IQueryable<T> Find<T>() where T : class;
      }
    }

How it works...

The mocking framework that we are using (called RhinoMocks) allows us to pass a fake object which can simulate the responses that a database would provide for us without having that connection. This allows us to keep our tests from being dependent on SQL data, and therefore brittle. Now that we have data available from our mock, we can test whether it acts exactly like we coded it to. Knowing the inputs of the data access code, we can test the outputs for validity.

This layering is accomplished by putting our Find method as an abstraction between the public framework method of Set<T> and our code, so we can change the type to something constructible. This is required due to the constructors of DbSet<T> being internal (not callable from any other assembly). By layering this method, we can now control every return from the database in the test scenarios.

This layering also provides for the better separation of concerns, as the DbSet<T> in Entity Framework mingles multiple independent concerns, such as connection management and querying, into a single object. We will continue to separate these concerns in future recipes.

There's more...

Testing to the edges of an application requires that we adhere to certain practices which allow us to shrink the untestable sections of the code. This will allow us to unit test more code, and make our integration tests far more specific.

One object under test

An important point to remember while performing unit testing is that we should only be testing a single class. The point of a unit test is to ensure that a single unit, a single class, performs the way we expect it to.

This is why simulating classes that are not under test is so important. We do not want the behavior of these supporting classes to affect the outcomes of unit tests for our class under test.

Integration tests

Often, it is equally important to test the actual combination of your various classes, to ensure they work properly together. These integration tests are valuable, but are almost always more brittle, require more setup, and are run slower than the unit tests. We certainly need integration tests on any project of a reasonable size, but we want unit tests first.

Arrange, act, assert

Most unit tests can be viewed as having three parts: arrange, act, and assert. Arrange is where we prepare the environment to perform the test, for instance, mocking of the IDBContext and setting up an expectation that Find<T> will be called. Act is where we perform the action under test and is most often a singular line of code. Assert is where we ensure that the proper result was reached. Note the comments in the examples above that call out these sections. We will use them throughout the book to make it clear what the test is trying to do.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset