How to fake IDbSet using Microsoft Fakes

While preparing to record a Microsoft Virtual Academy course on Build for 2015 I ran into the situation where I needed to test a controller that relied on a DbContext.  I thought this would be a great opportunity to document what it takes to do so.  For the purpose of this blog post we will be using a publically available project PartsUnlimited located here https://github.com/Microsoft/PartsUnlimited.  We will be working out of the aspnet45 branch.

With the project loaded in Visual Studio 2013 Update 4 let’s begin by adding a test project.

1.      Right click on src folder and select Add >> New Project...

2.      Select Test and select Unit Test Project.

3.      Change the .NET Framework to 4.5.1.

4.      Name the project "PartsUnlimitedWebsite.Test" and click OK.

With the test project added we need to make a reference to the PartsUnlimitedWebsite project.

1.      Right click on the PartsUnlimitedWebsite.Test project and select Add >> Reference…

2.      Select the Solution section on the left hand side.

3.      Check the box next to PartsUnlimitedWebsite and click OK.

We also need to add a reference to EntityFramework and Microsoft ASP.NET MVC.

1.      Right click on the solution and select Manage NuGet Packages for Solution…

2.      Select EntityFramework then click the Manage button.

3.      Check the box for PartsUnlimitedWebsite.Test and click OK.

4.     Select Microsoft ASP.NET MVC then click the Manage button.

5.     Check the box for PartsUnlimitedWebsite.Test and click OK.

6.      Now click Close on the PartsUnlimited.sln Manage NuGet Packages dialog.

Now we need to produce fakes for both the PartsUnlimtedWebsite and EntityFramework assemblies.

1.      Expand the References node under the PartsUnlimitedWebsite.Test project.

2.      Right click on EntityFramework and select Add Fakes Assembly.

3.      Right click on PartsUnlimitedWebsite and select Add Fakes Assembly.

Following the steps above will create a new Fakes folder in your project with two files EntityFramework.fakes and PartsUnlimited.fakes. The next section is optional.  If you build the solution right now you should build with no errors but you will have two warnings. The warnings will state that some fakes could not be generated.  The following steps will remove those warnings.

1.      Double click EntityFramework.fakes.

2.      Replace the file’s contents with the following:

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/" Diagnostic="true">

  <Assembly Name="EntityFramework" Version="6.0.0.0"/>

  <StubGeneration>

    <Clear/>

    <Add TypeName="IDbSet"/>

  </StubGeneration>

  <ShimGeneration>

    <Clear/>

  </ShimGeneration>

</Fakes>

3.      Double click PartsUnlimited.fakes.

4.      Replace the file’s contents with the following:

<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/" Diagnostic="true">

  <Assembly Name="PartsUnlimited"/>

  <StubGeneration>

    <Clear />

    <Add FullName="PartsUnlimited.Models.IPartsUnlimitedContext"/>

  </StubGeneration>

  <ShimGeneration>

    <Clear />

  </ShimGeneration>

</Fakes>

Making these changes are instructing the Fakes engine to only generate stubs for two types instead of the entire assembly.  This will get rid of the two warnings and reduce our build time.

With the stubs generated we can now turn our attention to writing the test.  We are going to create a test for the Index method of the HomeController class.  This method uses the DbContext class to try and retrieve products.  Our goal is to be able to call this method in a test without requiring access to a database. To do so we are going to fake the IPartsUnlimitedContext interface required by the HomeController constructor.

1.      Right click the UnitTest1.cs file and select Rename.

2.      Change the name to "HomeControllerTests" and press Enter.

3.      Click Yes on the dialog asking if you would like to rename all references.

4.      Rename the TestMethod1 method to "HomeContoller_Index".

5.      Finally replace the using statements at the top of the file with the following:

using Microsoft.VisualStudio.TestTools.UnitTesting;

using PartsUnlimited.Controllers;

using PartsUnlimited.Models;

using PartsUnlimited.Models.Fakes;

using System.Collections.Generic;

using System.Data.Entity.Fakes;

using System.Linq;

With the file, class and method renamed we can start writing our test. I use the triple A method of test writing so let’s add the Arrange, Act and Assert comments to frame our test.

public void HomeContoller_Index()

{

   // Arrange

 

   // Act

 

   // Assert

}

Most of our work will take place in the arrange section where we will fake our IPartsUnlimitedContext and IDbSet interfaces. Because we are going to be accessing the products we are going to create a sample product we can use in our test.  While building this test I realized that the OrderDetails collection of the product is accessed. When using Fakes you only have to fake the portions of your stubs that are accessed during the execution of your test.  Therefore, I only set the OrderDetails property of my product object.

var product = new Product

{

   OrderDetails = new List<OrderDetail>()

};

 

A DbSet in EntityFramework is a collection. So we are going to create a simple List to back our fake DBSet.  The only entry in this list will be the product we just created, however, you could add as many products as you need for your testing.

// Create a list to hold the products to be returned by the model context

var productList = new List<Product> { product };

Now it is time to fake the IPartsUnlimitedContext interface. This is the first time we will actually be using the generated types StubIPartsUnlimitedContext and StubIDbSet.  Fakes will create classes for us that we can use to code the desired behavior during our test.  As I mentioned before we only have to implement the portion of our stubs that are accessed during our test. Because we are only going to be working with the products table that is the only DbSet we are going to implement.

LINQ is used to query the DbSet which accesses two properties the Expression and the Provider.  Luckily we can use our list we created earlier to provide the expression and provider of our fake.

var context = new StubIPartsUnlimitedContext

{

   ProductsGet = () => new StubIDbSet<Product>()

   {

      ExpressionGet = () => productList.AsQueryable().Expression,

      ProviderGet = () => productList.AsQueryable().Provider

   }

};

Now comes the easy part.  Simply pass our fake IPartsUnlimitedContext to the constructor of our HomeController and call the Index method.

var target = new HomeController(context);

 

// Act

var actual = target.Index();

Finally you can now assert that some state is true.

// Assert

Assert.IsNotNull(actual);

Now you can run this test and even step through the code to see how the fakes allow you to test this code with no database.  Fakes is an incredible isolation framework for writing unit test.  You can learn more about fakes here

Add comment

Loading