Implementing a Customer Search Service – Part 2

Continuing on from my previous post, let’s start off by coding up the unit tests based on the behaviour scenarios we laid out. To ease my transition towards the BDD-like way of writing tests, I’m using xUnit along with a really handy base class and observation attribute developed by Fredrik Kalseth (check out his blog post here to see how this all works). As a refresher, the scenario I’ll be testing first is:

WHEN searching for customers

GIVEN customers exist matching the search criteria

THEN records matching the criteria will be retrieved from the persistence store AND customer summaries are returned AND the search is successful

And the coded test looks like this:

public class When_Searching_For_Customers 
              : Given_Customers_Exist_Matching_Criteria
{
    private ISearchResult<ICustomerSummary> _result;

    protected override void Observe()
    {
        ICustomerSearchService service = 
           new CustomerSearchService(_repository, _customerSummaryMapper);
        _result = service.Find(_criteria);
    }

    [Observation]
    public void Records_Matching_criteria_are_requested_from_repository()
    {
        Assert.Equal(1, _repositoryInvocationCount);
    }

    [Observation]
    public void Customer_Summaries_are_returned()
    {
        Assert.NotNull(_result.Hits);
    }

    [Observation]
    public void The_Search_is_successful()
    {
        Assert.True(_result.IsSuccessful);
    }
}

Pretty simple stuff. Following the Arrange, Act, Assert pattern for authoring tests, the “arranging” of the test takes place in the base class (which I’ll cover shortly), the “act” takes place by creating and invoking the service,  and finally there is then an assertion for each observation that we are hoping to prove.

The base class that manages the set-up of the test context looks like this:

public abstract class Given_Customers_Exist_Matching_Criteria 
                       : Specification
{
    protected IRepository<Customer> _repository;
    protected ICustomerSummaryMapper _customerSummaryMapper;
    protected ISearchCriteria<Customer> _criteria;
    protected int _repositoryInvocationCount;

    protected override void InitializeContext()
    {
        _repository = GetMockRepository();
       _customerSummaryMapper = GetMockCustomerMapper();
    }

    private static ICustomerSummaryMapper GetMockCustomerMapper()
    {
        var mock = new Mock<ICustomerSummaryMapper>();
        mock.Expect(map => map.MapFrom(It.IsAny<IList<Customer>>()))
            .Returns(new List<ICustomerSummary>());
        return mock.Object;
    }

    private IRepository<Customer> GetMockRepository()
    {
        var mockRepository = new Mock<IRepository<Customer>>();
        var mockCustomers = GetMockCustomers();
        mockRepository.Expect(rep => rep.Find(_criteria))
            .Returns(mockCustomers)
            .Callback(() => _repositoryInvocationCount++);
        return mockRepository.Object;
    }

    private static IList<Customer> GetMockCustomers()
    {
        var mockCustomers = new Mock<IList<Customer>>();
        mockCustomers.Expect(customers => customers.Count).Returns(10);
        return mockCustomers.Object;
    }
}

This class simply creates mocks for the dependencies of the SUT, such that we can test the unit in isolation. The only little extra here is that the mock repository behaves more like a test spy, since it allows us to monitor the number of times that the Find() method has been invoked.

 

Implementing the Service

Since I want to be completely flexible with my search criteria, I want the contract of my service to take in an abstraction of the Customer search criteria, rather than specifying a finite set of inputs. I think the following contract describes this quite well:

ISearchResult<ICustomerSummary> Find(ISearchCriteria<Customer> criteria);

 

I don’t want any of my data retrieval responsibilities leaking into the application layer. This work should be delegated repository. I therefore want my service to pass-through the search parameters into a repository implementation. Rather than making the repository aware of the presentation layer object ISearchCriteria, it is better to use a common, shared abstraction. A suitable abstraction to use here would be to use the specification pattern for the search criteria, and passing this abstraction to the repository.

As discussed briefly in my previous posts (and in detail here), I believe my repository should behave like a collection of entities (rather than serving up a query in the form IQueryable<T>). I also know my repository can only return a reference to entities defined as the root of an Aggregate.

Taking all this into account, I can specify my repository interface as:

public interface IRepository<TAggregateRoot>
    where TAggregateRoot : class, IAggregateRoot
{
    /// <summary>
    /// Find entities by specification.
    /// </summary>
    IList<TAggregateRoot> Find(ISpecificationExpression<TAggregateRoot> criteria);
}

NB: It’s likely that my Repository Interface will later include the ability to save new and updated entities, however as per YAGNI, I won’t include this for the moment.

 

Since my repository can only return a reference to an Aggregate Root, the Customer aggregate root will need to be mapped to the required CustomerSummary presentation object. A suitable interface for this mapper object could be:

ICustomerSummary MapFrom(Customer customer);
IEnumerable<ICustomerSummary> MapFrom(IList<Customer> customers);

All that remains then is to create an implementation of the service based on these interfaces. This is quite simply:

public ISearchResult<ICustomerSummary> Find(ISearchCriteria<Customer> criteria)
{
    var customers = _repository.Find(criteria);

    if (customers == null || customers.Count == 0)
    {
        return new CustomerSearchResult
        {
            IsSuccessful = false,
            FailureReasons = new[] { "No Customers found." }
        };
    }

    var summary = _mapper.MapFrom(customers);

    return new CustomerSearchResult { IsSuccessful = true, Hits = summary };
}

 

All that’s left is to create simple implementations for the remaining objects (CustomerSearchResult, CustomerSummary CustomerSearchCriteria) and we’re ready to rock. Now the logic of the Application Service is created and the tests pass, we can create a repository implementation making use of the Entity Framework sample’s EFPocoAdapter project. I’ll cover this in my next post.

Advertisements

About craigcav

Craig Cavalier works as a Software Developer for Liquid Frameworks in Houston Tx, developing field ticketing and job management solutions for industrial field service companies.

Posted on October 12, 2008, in Behaviour Driven Development, Domain Driven Design, Entity Framework, Persistence Ignorance, Unit Testing. Bookmark the permalink. 4 Comments.

  1. This is right what i needed… Despite that i didn`t find any source code – thanks.

  1. Pingback: What purpose does the Repository Pattern have? « Cav’s Weblog

  2. Pingback: Active Blogger?! « Cav’s Weblog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: