In previous part we saw how to implement a Repository pattern over Linq2SQL. Let’s see in more detail how we can test this. If you are not new to unit testing and mocking, feel free to skip.

Suppose we have a controller that is using a IRepository<Product> and we need to have two in-memory products returned when querying. Basically, the controller itself looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class HomeController : Controller
{
public HomeController(IRepository<Product> productRepository, IRepository<Customer> customerRepository)
{
_productRepository = productRepository;
_customerRepository = customerRepository;
}

public ActionResult QueryProducts()
{
var products = _productRepository.FindMany(p => p.OrderLines.Count > 0);

ViewData["Message"] = string.Format("There are {0} products sold.", products.Count());

return View("Index");
}
}

and the test would be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class HomeControllerTests
{
[Fact]
public void Can_Query_Products_With_An_Orders()
{
var products = new[]
{
new Product { Name = "TV", OrderLines = new EntitySet<OrderLine> { new OrderLine() } },
new Product { Name = "Laptop", OrderLines = new EntitySet<OrderLine> { new OrderLine() } },
};

var customersRepo = MockRepository.GenerateStub<IRepository<Customer>>();
var productRepo = ??
var controller = new HomeController(productRepo, customersRepo);

controller.QueryProducts();

Assert.Equal("There are 2 sold products.", controller.ViewData["Message"]);
}
}

So how do we create a IRepository<Product>? Do we mock it using the interface? Do we create the implementation that accepts our in-memory collection? The first thing that’d come to mind is to create a mock object using the interface:

1
productRep.Expect(r => r.FindMany(Arg<Func<Product, bool>>.Is.Anything)).Return(products);

There are some things that I’m not happy with. The arguments are over-specified and if you try to create a more specific one for FindMany method, it would result a somewhat unreadable code. But as far as running and passing the test goes, it is okay and runs fine. The second way to go is to create another constructor on Repository<T> that accepts IEnumerable<T> for the in-memory data. We’ll use this overload just in tests.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Repository<T> : IRepository<T> where T : class
{
private readonly DataContext _context;
private readonly IQueryable<T> _data;

public Repository(DataContext context, IEnumerable<T> data)
{
_context = context;
_data = data.AsQueryable();
}

public Repository(DataContext context)
{
_context = context;
_data = Table;
}

public virtual T FindOne(Func<T, bool> criteria)
{
return _data.Where(criteria)
.FirstOrDefault();
}
}

This way too has its downsides. It is a little intrusive (having an API that should be called in tests only) but will lead to a more readable test. In the test, instead of mocking the interface we can now create the implementation and pass in the collection. There’s no need to setup a mock object:

1
var productRepo = new Repository<Product>(new DataContextStub(), products);

Testing the CRUD operations is pretty straight forward. Let’s say the controller has an action that creates a customer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public ActionResult CreateCustomer()
{
var c = new Customer
{
Firstname = "John",
Lastname = "Doe",
};

_customerRepository.Insert(c);
_customerRepository.Save();

ViewData["Message"] = "Customer created successfully!";

return View("Index");
}

There are two things to test here. First checking the correct customer is being saved, the second part is to make sure Save operation is called. We could also check the message being displayed but let’s skip it for brevity reasons.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[Fact]
public void CreateNewCustomer_Inserts_A_New_Customer()
{
var customersRepo = MockRepository.GenerateMock<IRepository<Customer>>();
var productRepo = MockRepository.GenerateStub<IRepository<Product>>();
var controller = new HomeController(productRepo, customersRepo);

controller.CreateCustomer();

customersRepo.AssertWasCalled(x => x.Insert(Arg<Customer>.Matches(c => c.Lastname == "Doe" &amp;&amp;
c.Firstname == "John")));
}

[Fact]
public void CreateNewCustomer_Saves_Changes_Into_Database()
{
var customersRepo = MockRepository.GenerateMock<IRepository<Customer>>();
var productRepo = MockRepository.GenerateStub<IRepository<Product>>();
var controller = new HomeController(productRepo, customersRepo);

controller.CreateCustomer();

customersRepo.AssertWasCalled(x => x.Save(), opt => opt.Repeat.Once());
}

If you need to test the Repository<T> implementation it’d be next to impossible using .NET FX 3.5. Why? Because the Table<T> class is sealed and you can not mock sealed classes (not with conventional tools that is, but you can given the right tool for the job). The solution? the easiest one would be to upgrade to .NET 4.0. Doing so, there is a ITable<T> interface which you can use to mock out the tables in the data context. You may download the whole source code from here.