Showing posts with label Unit Testing. Show all posts
Showing posts with label Unit Testing. Show all posts

Thursday, October 15, 2009

Budget App - Part 4 : Test Driven Development with Moq - An New .Net Mocking Framework

I recently found a relatively new Mocking Framework called Moq. Daniel Cazzulino provides a nice introduction and reason for developing the new framework. Considering that this is built on the concept of Linq to Mock and that I enjoy working with Linq I thought I'd give it ago as I continue to develop the data services to my Budget application with a TDD approach.

I'm going to following the principles of TDD as I understand them:
  1. Write the test first - it'll probably not compile.
  2. Get the test to compile.
  3. Get the test to pass - with the least amount of code.
  4. Create another test that will cause your code to fail.
  5. Refactor your class so that both tests pass.
Write the test first
As I've been refactoring my code I've come across the follow functionality...

private bool DoesMonthYearExis( int month, int year )
{
    bool exists = false;

    var months = ( from m in budgetEntities.MthSet
                   where m.Month == month && m.Year == year
                   select m ).ToList();

    if ( months.Count > 0 )
    {
        exists = true;
    }

    return exists;
}

There will obviously be a number of steps involved in turning this into a WCF Service call, but the first step is to ensure that the DataService will do what it's suppose to do. So how do we do this using a TDD approach? Firstly we write our test.



So here we have our first test using the new Moq framework. As you can see the data service interface doesn't have a definition for a method called DoesMonthYearExist(...) hence it won't compile, which leads to...

Getting the test to compile
To get this to compile we need to update the Interface as well as it's implementing class. We need to remember that we write the least amount of code as possible.



This obviously isn't very useful, but it should give you point. The test will now compile however it will fail. If you look at the test above there we have set up a number of expectations with Moq and these aren't being met. Now let's...

Get the test to pass
Don't forget to write as little code as possible.


You can see that the expectations will now be met with repo.Query() returning a value and the repo object being disposed.

This is all good, but we know that the code is not really doing what we need it to do and this is when we...

Create another test that will cause your code to fail
Not a huge difference, but it's enough.


We've changed the year being tested for and are now expecting that the combination of month and year will not be found.

Refactor your class so that both tests pass
Here we make our implementation do what it's supposed to do.



What does this leave us with? A well tested method that has good coverage

Moq
I must say that I do like not having to indicate what expectations have to be recorded and then play them back, you just say this object has certain expectations and that's it.

Despite simple examples Moq looks like a nice mocking framework to work with.

Enjoy!

Wednesday, September 2, 2009

Budget App - Part 3 : Unit Testing Data Services with Rhino Mocks

Repository Pattern
The nest step in building my Budget application was ensuring that it could be unit tested. In my googling I came to realise the my design could be improved somewhat. I have now introduced the repository pattern with the interface looking like this...

IRepository.cs
public interface IRepository<T> : IDisposable
{
    IQueryable<T> Query();
    void Add( T entity );
    void Attach( T entity );
    void Remove( T entity );
    void SubmitChanges();
}

and its implementation looking like this...

BudgetRepository.cs
public class BudgetRepository<T> : IDisposable, IRepository where T : class
{
    private BudgetDataContext context;

    public BudgetRepository( BudgetDataContext ctxt )
    {
        context = ctxt;
    }

    public IQueryable<T> Query()
    {
        return context.GetTable<T>();
    }

    public void Add( T entity )
    {
        context.GetTable<T>().InsertOnSubmit( entity );
    }

    public void Attach( T entity )
    {
        context.GetTable<T>().Attach( entity );
    }

    public void Remove( T entity )
    {
        context.GetTable<T>().DeleteOnSubmit( entity );
    }

    public void SubmitChanges()
    {
        context.SubmitChanges();
    }

    public void Dispose()
    {
        context.Dispose();
    }
}

The repository is obviously providing access to an individual table via the generic type used. Now all that is needed is to write some services to utilise the repository. The first service to be written was an IncomeDataService.

IncomeDataService.cs
public class IncomeDataService
{
    private IRepository<Income> incomeRepository;

    public IncomeDataService( IRepository<Income> repository )
    {
        incomeRepository = repository;
    }

    public IList<Income> GetAll()
    {
        IList<Income> incomes;
        using ( incomeRepository )
        {
            incomes = ( from i in incomeRepository.Query()
                        orderby i.Description
                        select i ).ToList();
        }
        return incomes;
    }

    public Income GetById( int ID )
    {
        Income income;
        using ( incomeRepository )
        {
            income = incomeRepository.Query().Where( i => i.IncomeId == ID ).FirstOrDefault();
        }
        return income;
    }

    public void Save( Income entity )
    {
        using ( incomeRepository )
        {
            if ( entity.IncomeId > 0 )
            {
                incomeRepository.Attach( entity );
            }
            else
            {
                incomeRepository.Add( entity );
            }
            incomeRepository.SubmitChanges();
        }
    }
}

Unit Testing with Rhino Mocks
Before continuing with all my services, I really want to be able to Unit Test my services to for a number of reasons. Firstly, if any potential employer views any of these posts then I can demonstrate good practises and secondly unit testing is a sure way to ensure that you code is doing what it should be doing.

I actually had a little bit of difficulty mocking my DataService but I finally got it out. I'd read a number of blogs on mocking the IQueryable object and that was easy but I was getting a number of odd errors once I passed my mocked repository into my service. Eventually I ended up with the following. Not sure what it was that clicked, but something did.

[TestMethod()]
public void GetIncomeByIdTest()
{
    // setup test collection
    IList<Income> incomeList = new List<Income>();
    Income expectedIncome = new Income() { IncomeId = 1 };
    Income unexpectedIncome = new Income() { IncomeId = 2 };
    incomeList.Add( expectedIncome );
    incomeList.Add( unexpectedIncome );

    MockRepository mocks = new MockRepository();
    IRepository repository = mocks.StrictMock<IRepository<Income>>();
    IncomeDataService svc = new IncomeDataService( repository );

    int actualID = 1;

    using ( mocks.Record() )
    {
        repository.Expect( repo => repo.Query() ).Return( incomeList.AsQueryable<Income>() );
        repository.Expect( repo => repo.Dispose() );
    }

    using ( mocks.Playback() )
    {
        Income actualIncome = svc.GetById( actualID );
        Assert.AreEqual( expectedIncome.IncomeId, actualIncome.IncomeId );
    }
}

So what is actually going on here?

This unit test is is aimed at testing the IncomeDataService class. The issue we face is that it requires an instance of a repository, but we obviously don't want to use the database for testing, hence we use Rhino Mocks to create a mock object of a repository.

We use the the statement using ( mocks.Record() ) to indicate what we expect to occur when the service calls the method GetById(...). So what do we expect to occur? That the repository will return the incomeList collection as an IQueryable collection and then call it's Dispose() method. Then the statement using (mocks.Playback() ) ensures that the expectations set out during the recording are used. So if we look at the GetById method...
using ( incomeRepository )
{
    income = incomeRepository.Query().Where( i => i.IncomeId == ID ).FirstOrDefault();
}
when the incomeRepository.Query() is called Rhino Mocks ensures that the List of Income objects setup at the beginning of the test are returned. Likewise when we exit the using statement the Dispose() method is called next.

Hope this helps!
Enjoy