Monday, January 9, 2012

Simple Circles–Fake Repository (Part 3)

This post is part of a series on building a simple to use web-based contact and customer relationship management application. The goal is to support various audiences including businesses, teams, clubs, religious organizations, etc. With a basic structure for the domain objects taking shape it’s time to move on to the notion of persistence.

In the last post I set up the interfaces to support the Repository pattern and left off with the following signature:

namespace Circles.Persistence
{
using System;
using System.Linq;

public interface IPartyRepository : IRepository<Party, Guid>, ISupportSave<Party, Guid>, ISupportDelete<Party, Guid>
{
IQueryable<Household> FindAllHouseholds();
IQueryable<Organization> FindAllOrganizations();
IQueryable<Person> FindAllPersons();
}

Now I’m going to put together a simple fake repository implementation to exercise the interfaces as well as quickly provide sample data to work with. I’ve added a new project called FakeRepository containing a single class called FakePartyRepository partly shown here:

namespace Circles.FakeRepository
{
using System;
using System.Collections.Generic;
using System.Linq;

public class FakePartyRepository : IPartyRepository
{
private readonly List<Household> fakeHouseholdList = new List<Household>
{
new Household { PartyName = "Churchill", FormalGreeting = "Sir Winston and Lady Clementine" },
new Household { PartyName = "Roosevelt", FormalGreeting = "President Franklin and Mrs. Eleanor" },
};

private readonly List<Organization> fakeOrganizationList = new List<Organization>
{
new Organization { PartyName = "Great Lakes Food Market" },
new Organization { PartyName = "Hungry Coyote Import Store" },
new Organization { PartyName = "Lazy K Kountry Store" },
};

private readonly List<Person> fakePersonList = new List<Person>
{
new Person { FirstName = "Nancy", LastName = "Davolio", Gender = GenderEnum.Female, Birthday = new DateTime(1948, 12, 8) },
new Person { FirstName = "Andrew", LastName = "Fuller", Gender = GenderEnum.Male, Birthday = new DateTime(1992, 8, 14) },
};

private readonly IQueryable<Household> fakeHouseholdRepository;
private readonly IQueryable<Organization> fakeOrganizationRepository;
private readonly IQueryable<Person> fakePersonRepository;
private readonly IQueryable<Party> fakePartyRepository;

public FakePartyRepository()
{
this.fakeHouseholdRepository = this.fakeHouseholdList.AsQueryable();
this.fakeOrganizationRepository = this.fakeOrganizationList.AsQueryable();
this.fakePersonRepository = this.fakePersonList.AsQueryable();
this.fakePartyRepository = this.fakeOrganizationList.Union(this.fakePersonList).Union(this.fakeHouseholdList).AsQueryable();
}

public IQueryable<Party> FindAll()
{
return this.fakePartyRepository;
}

public Party FindById(Guid id)
{
return this.fakePartyRepository.FirstOrDefault(x => x.PartyId == id);
}
}

As you can see, the underlying data is contained in simple in-memory generic Lists that are wrapped into LINQ IQueryable objects. Note the last line of the constructor where the fakePartyRepository is a .Union of the three underlying lists.


Simple Circles - xunitTo test the FakeRepository let’s add another class library project called UnitTests. We’ll use NuGet to add the xUnit package with the command ‘install-package xunit’ as shown to the right. xUnit was created by James Newkirk (creator of the venerable NUnit) and Brad Wilson to better reflect the purpose of driving and iterating the design of an implementation at the unit level. Brad discusses this philosophy in his article Its not TDD, It’s Design by Example. After adding the xUnit reference, add a class called PartyRepositoryTest:

  public class PartyRepositoryTest
{
[Fact]
public void CanAddHousehold()
{
// arrange
IPartyRepository repository = new FakePartyRepository();

// act
var id = repository.Add(new Household
{
PartyName = "Eisenhower",
FormalGreeting = "President Dwight D. and Mrs. Mamie",
InformalGreeting = "Ike and Mamie"
});

// assert
Assert.NotNull(id);
Assert.NotNull(repository.FindById(id));
}
}

The first thing you may notice is that xUnit uses the attribute [Fact] rather than [Test] as other TDD frameworks do. As Brad puts it “a [Fact] is an expression of some condition which is invariant”. Essentially we’re saying that the condition “CanAddHousehold” is an invariant condition of the PartyRepository which must always be true. In addition to expressing facts, xUnit lets you express theories which are “an expression of a condition which is only necessarily true for the given set of data.”:

  [Theory,
InlineData("D28AA45E-C650-4121-8070-3D12BE31F91A")]
public void CanFindSinglePerson(string id)
{
// arrange
IPartyRepository repository = new FakePartyRepository();
var partyId = new Guid(id);

// act
var person = repository.FindById(partyId) as Person;

// assert
Assert.NotNull(person);
Assert.True(person.Id == partyId);
}

Simple Circles - Unit TestsSince we built the FakeRepository with our known data, we can construct tests with known values to prove the repository is working as designed without defects. In the above example, we know the PartyId of one of the person instances that we put into the fake repository so we can attempt to retrieve that person to exercise that logic. ReSharper’s test runner shows all the tests we currently have. Before the tests can be compiled and run, you must add a reference to the Extensions subproject of xUnit which holds the [Theory] attribute definition and behavior. Once again, use the NuGet Package Manager Console to execute the command “install-package xunit.extensions”.


Finally, you’ll notice in the above samples as well as the source code accompanying this post that I’ve followed the “3A” or “Arrange-Act-Assert” principle for writing the tests.


The source code for this article can be downloaded from here.


Next we’ll look at starting an ASP.NET MVC 3 website to consume and present the domain model.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.