EF CTP4 Tips & Tricks: Testing With Fake DbContext

Posted on September 7, 2010. Filed under: Entity Framework | Tags: , , , , , , , , |

 


This post is based on a pre-release version of Entity Framework.

An updated post is available here.


 

 

This is the sixth in a series of posts about the recently released Entity Framework Feature CTP4, now affectionately known as “EF Magic Unicorn Edition”.

In this post we are going to take a look at how to replace a DbContext based data access layer with an in-memory fake for unit testing.

I’m going to use an MVC controller as an example but the same approach can be used for any component that consumes a derived DbContext, including repositories.

The Problem

Say we have a very simple model for Employees and Departments and we are using DbContext in Code First mode to persist and query our data:

public class EmployeeContext : DbContext
{
    public DbSet<Department> Departments { get; set; }
    public DbSet<Employee> Employees { get; set; }
}

public class Department
{
    public int DepartmentId { get; set; }
    public string Name { get; set; }

    public ICollection<Employee> Employees { get; set; }
}

public class Employee
{
    public int EmployeeId { get; set; }
    public int FirstName { get; set; }
    public int LastName { get; set; }
    public int Position { get; set; }

    public Department Department { get; set; }
}

In an MVC application we could add a controller that can display all departments in alphabetical order and allow us to add new departments:

(Typically we’d also implement ‘detail’, ‘edit’ and ‘delete’ functionality but I’m leaving them out because ‘list’ and ‘create’ are enough to demonstrate fakes)

public class DepartmentController : Controller
{
    private EmployeeContext context;

    public DepartmentController()
    {
        this.context = new EmployeeContext();
    }

    public ViewResult Index()
    {
        return View(this.context.Departments.OrderBy(d => d.Name).ToList());
    }

    public ViewResult Create()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Create(Department dep)
    {
        context.Departments.Add(dep);
        context.SaveChanges();
        return RedirectToAction("Index");
    }
}

The issue is that our controller now has a hard dependency on EF because it needs an EmployeeContext which derives from DbContext and exposes DbSets. We have no way to replace this with any other implementation and we are forced to run any unit tests against a real database, which means they really aren’t unit tests at all.

Adding an Interface

DbSet<T> happens to implement IDbSet<T> so we can pretty easily create an interface that our derived context implements:

public interface IEmployeeContext
{
    IDbSet&lt;Department&gt; Departments { get; }
    IDbSet&lt;Employee&gt; Employees { get; }
    int SaveChanges();
}

public class EmployeeContext : DbContext, IEmployeeContext
{
    public IDbSet&lt;Department&gt; Departments { get; set; }
    public IDbSet&lt;Employee&gt; Employees { get; set; }
}

Now we can update our controller to be based on this interface rather than the EF specific implementation. You’ll notice I’m still using the EF implementation in the default constructor, in a real world app you would probably just have the interface based constructor and use dependency injection to supply the EF implementation at runtime, but I just wanted to keep things simple for this post :)

public class DepartmentController : Controller
{
    private IEmployeeContext context;

    public DepartmentController()
    {
        this.context = new EmployeeContext();
    }

    public DepartmentController(IEmployeeContext context)
    {
        this.context = context;
    }

    public ViewResult Index()
    {
        return View(this.context.Departments.OrderBy(d =&gt; d.Name).ToList());
    }

    public ViewResult Create()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Create(Department dep)
    {
        context.Departments.Add(dep);
        context.SaveChanges();
        return RedirectToAction(&quot;Index&quot;);
    }
}

Building Fakes

The first thing we need is a fake implementation of IDbSet<TEntity>, this is pretty easy to implement.

public class FakeDbSet&lt;T&gt; : IDbSet&lt;T&gt;
    where T : class
{
    HashSet&lt;T&gt; _data;
    IQueryable _query;

    public FakeDbSet()
    {
        _data = new HashSet&lt;T&gt;();
        _query = _data.AsQueryable();
    }

    public virtual T Find(params object[] keyValues)
    {
        throw new NotImplementedException(&quot;Derive from FakeDbSet&lt;T&gt; and override Find&quot;);
    }

    public void Add(T item)
    {
        _data.Add(item);
    }

    public void Remove(T item)
    {
        _data.Remove(item);
    }

    public void Attach(T item)
    {
        _data.Add(item);
    }

    public void Detach(T item)
    {
        _data.Remove(item);
    }

    Type IQueryable.ElementType
    {
        get { return _query.ElementType; }
    }

    System.Linq.Expressions.Expression IQueryable.Expression
    {
        get { return _query.Expression; }
    }

    IQueryProvider IQueryable.Provider
    {
        get { return _query.Provider; }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    IEnumerator&lt;T&gt; IEnumerable&lt;T&gt;.GetEnumerator()
    {
        return _data.GetEnumerator();
    }
}

The one thing you’ll notice is that there isn’t really a good way to generically implement Find so I’ve left it as a virtual method that throws if called. If our application makes use of the Find method we can create an implementation specific to each type:

public class FakeDepartmentSet : FakeDbSet&lt;Department&gt;
{
    public override Department Find(params object[] keyValues)
    {
        return this.SingleOrDefault(d =&gt; d.DepartmentId == (int)keyValues.Single());
    }
}

public class FakeEmployeeSet : FakeDbSet&lt;Employee&gt;
{
    public override Employee Find(params object[] keyValues)
    {
        return this.SingleOrDefault(e =&gt; e.EmployeeId == (int)keyValues.Single());
    }
}

Now we can create a fake implementation of our context:

public class FakeEmployeeContext : IEmployeeContext
{
    public FakeEmployeeContext()
    {
        this.Departments = new FakeDepartmentSet();
        this.Employees = new FakeEmployeeSet();
    }

    public IDbSet&lt;Department&gt; Departments { get; private set; }

    public IDbSet&lt;Employee&gt; Employees { get; private set; }

    public int SaveChanges()
    { return 0; }
}

Testing Against Fakes

Now that we have our fakes defined we can use them to write a unit test for our controller, that doesn’t use EF:

[TestMethod]
public void IndexOrdersByName()
{
    var context = new FakeEmployeeContext
    {
        Departments =
        {
            new Department { Name = &quot;BBB&quot;},
            new Department { Name = &quot;AAA&quot;},
            new Department { Name = &quot;ZZZ&quot;},
        }
    };

    var controller = new DepartmentController(context);
    var result = controller.Index();

    Assert.IsInstanceOfType(result.ViewData.Model, typeof(IEnumerable&lt;Department&gt;));
    var departments = (IEnumerable&lt;Department&gt;)result.ViewData.Model;
    Assert.AreEqual(&quot;AAA&quot;, departments.ElementAt(0).Name);
    Assert.AreEqual(&quot;BBB&quot;, departments.ElementAt(1).Name);
    Assert.AreEqual(&quot;ZZZ&quot;, departments.ElementAt(2).Name);
}

Summary

In this post we saw how to build an interface that represents our context and how to build an in-memory fake of that context for use in our unit tests. We used an MVC controller to demonstrate this but the same approach can be used with any component that needs to interact with an EF based context, including repositories. There are a number of reasons to use in-memory fakes for unit testing but some key benefits are stable and robust tests that execute quickly and exercise a single component, making failures easy to isolate.

About these ads

Make a Comment

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

35 Responses to “EF CTP4 Tips & Tricks: Testing With Fake DbContext”

RSS Feed for RoMiller.com Comments RSS Feed

This is awesome,I was going to ask about this 2 days ago,good timing you posted this.

Thanks :)

Nice.. I like all your blog post.. Just added you to my favorite list.

This is exactly what I was looking for. Thanks a lot for the post. BTW, I have a blog in portuguese and I´d like to ask you for permission to translate yours CTP4 series in it. May I?

Yes, please feel free to translate any content!

Hi, love the post. I am having problems after doing this though creating a generic set. I.e. the below doesnt work anymore bacause IMyContext doesnt have set. Thanks for the great article.
private IMyContext context;
public IList List()
{
return context.Set().ToList();
}

Hi,
You would just need to add a Set method to your interface, you probably want it to return an IDbSet rather than a DbSet so you would need to implement the method on you derived context:

public interface IEmployeeContext
{
IDbSet˂Department˃ Departments { get; }
IDbSet˂Employee˃ Employees { get; }
int SaveChanges();

IDbSet˂TEntity˃ Set˂TEntity˃() where TEntity : class;
}

public class EmployeeContext : DbContext, IEmployeeContext
{
public IDbSet˂Department˃ Departments { get; set; }
public IDbSet˂Employee˃ Employees { get; set; }

public new IDbSet˂TEntity˃ Set˂TEntity˃() where TEntity : class
{
return base.Set˂TEntity˃();
}
}

~Rowan

This tutorial is great, however I’m getting a compile error on the following. As far as I can tell, all of my interfaces and classes are set up according to your outline above, but for some reason the line below won’t compile. The error message is at the end. Any advice would be great, thanks and keep up the good work!

var context = new FakeContext
{
// This errors…
Categories = new Category { CategoryId = 1, CategoryName= “Test Category”, CategoryDescription=”Category Description”, SortOrder=1 }
};

Cannot implicitly convert type ‘Commerce.Data.Model.Category’ to ‘System.Data.Entity.IDbSet’. An explicit conversion exists (are you missing a cast?)

Never mind… I found my problem… I needed to do this instead:

Categories = { new Category {CategoryId = 1, CategoryName= “Test Category”, CategoryDescription=”Category Description”, SortOrder=1 }}

I have never used the MVC and completely new to the idea of fake.
Suppose we use the real data from the database and let the fake process it through a series of nested for loops, inserting the processed result into a table in the fake, all in the memory.
After we get the result can we transfer/persist the result back to the real database?
I am thinking of using this approach not so much for testing but that I think it is faster to insert into a table in the fake rather than making a few thousands of round trips to the database by inserting a row in the database after each successful step in a for loop using savechanges.

CTP 5 Version:

public class FakeDbSet : IDbSet
where T : class
{
readonly HashSet _data;
readonly IQueryable _query;

public FakeDbSet()
{
_data = new HashSet();
_query = _data.AsQueryable();
}

public virtual T Find(params object[] keyValues)
{
throw new NotImplementedException(“Derive from FakeDbSet and override Find”);
}

public T Add(T item)
{
_data.Add(item);
return item;
}

public T Remove(T item)
{
_data.Remove(item);
return item;
}

public T Attach(T item)
{
_data.Add(item);
return item;
}

public void Detach(T item)
{
_data.Remove(item);
}

Type IQueryable.ElementType
{
get { return _query.ElementType; }
}

Expression IQueryable.Expression
{
get { return _query.Expression; }
}

IQueryProvider IQueryable.Provider
{
get { return _query.Provider; }
}

IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}

public TDerivedEntity Create() where TDerivedEntity : class, T
{
return Activator.CreateInstance();
}

public T Create()
{
return Activator.CreateInstance();
}

public ObservableCollection Local
{
get {

return new ObservableCollection(_data);
}
}

}

@Lee – nice code, but you left out the T in the class declaration above.

public class FakeDbSet : IDbSet

Caused a bit of head scratching here for a while…

Oh – the T gets removed by the blog software!

James

Hi!

I am having a problem getting DbEntityEntry as the return type.

Can you help?

public System.Data.Entity.Infrastructure.DbEntityEntry Entry(T entity) where T : class
{
DbSetFake fakes = new DbSetFake();
fakes.FirstOrDefault();

return null;
}

I am having similiar issue with getting the DbEntityEntry back out from implementing this method:

DbEntityEntry Entry(T entity) where T : class;

Here is my IDbContext interface:

public interface IDbContext : IDisposable
{
IDbSet Products { set; get; }
IDbSet Customers { set; get; }

DbEntityEntry Entry(T entity) where T : class;
int SaveChanges();
}

Here is my implementations:

public class DbContextFake : IDbContext
{
public DbContextFake()
{
this.Products = new ProductSetFake();
this.Customers = new CustomerSetFake();

}

public IDbSet Products { set; get; }
public IDbSet Customers { set; get; }

public System.Data.Entity.Infrastructure.DbEntityEntry Entry(T entity) where T : class
{
??????????????

//not sure how to return a DbEntityEntry object from the entity of type T though..
//can anyone help please????
}

public int SaveChanges()
{
return 0;
}

public void Dispose()
{
return;
}
}

Thanks.

CTP5 Version

public class FakeDbSet : IDbSet where T : class
{
readonly HashSet _data;
readonly IQueryable _query;

public FakeDbSet()
{
_data = new HashSet();
_query = _data.AsQueryable();
}

public virtual T Find(params object[] keyValues)
{
throw new NotImplementedException(“Derive from FakeDbSet and override Find”);
}

public T Add(T item)
{
_data.Add(item);
return item;
}

public T Remove(T item)
{
_data.Remove(item);
return item;
}

public T Attach(T item)
{
_data.Add(item);
return item;
}

public void Detach(T item)
{
_data.Remove(item);
}

Type IQueryable.ElementType
{
get { return _query.ElementType; }
}

Expression IQueryable.Expression
{
get { return _query.Expression; }
}

IQueryProvider IQueryable.Provider
{
get { return _query.Provider; }
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}

public T Create()
{
return Activator.CreateInstance();
}

public ObservableCollection Local
{
get
{
return new ObservableCollection(_data);
}
}

public TDerivedEntity Create() where TDerivedEntity : class, T
{
return Activator.CreateInstance();
}
}

Thanks, Peterlin!

But I think your reply does not solve the problem. Here is the problem:

I have a repository that has a method like this:

public bool Update(Product entity)
{
try
{
this.context.Products.Attach(entity);
this.context.Entry(entity).State = EntityState.Modified;
return true;
}
catch
{
return false; }
}

My Unit Test:

///
///A test for Update
///
[TestMethod()]
public void CanUpdateTest()
{
//the fake DbContext to be constructor injected into the real repository implementation.
DbContextFake fakeDbContext = new DbContextFake();
//the real target ProductRepository implementation that accepts a IDbContext: DbContextFake implements IDbContext as above.
ProductRepository target = new ProductRepository(fakeDbContext);

//add a new product to the fake context object graph
Product product=new Product(123);
product.Description = “Added Product”;
fakeContext.Products.Add(product);
fakeContext.SaveChanges();

//get that product out using the product id
Product updateProduct = fakeContext.Products.Find(product.Id);

//make a change
updateProduct.Description = “My updated product”;

bool expected = true;
bool actual = false;

//act: now update this poor product.
actual = target.Update(updateProduct);

//assert
Assert.AreEqual(expected, actual);
}

Where it blows up:

this.context.Entry(entity).State = EntityState.Modified;

The exception is : this.context.Entry is NULL.

The reason for this is because IDbContext or IEmployeeContext above does not contain a method for this:

DbEntityEntry Entry(T entity) where T: class

If you add this method into your IDbContext or IEmployeeContext and implement it in your DBContextFake : IDbcontext

The question is : how do you implement this method that would give you a return type of

DbEntityEntry within this method?

Hi Christine, did you solve your issue with DbEntityEntry? I’m having the same problem.
Thanks,

Great post, I like this a lot better than many of the other EF code first repository pattern options I’ve seen online. One thing to note for the Find method, if you have a naming convention for IDs in your app like I do (I name all PKs “Id”), you can use reflection to create a standard Find that will work in most cases:

public virtual T Find(params object[] keyValues)
{
// Assume there is an Id property, or else throw. We could also look for properties with [DatabaseGenerated(DatabaseGenerationOption.Identity)] attributes…
try
{
Type tType = typeof(T);
PropertyInfo idProperty = tType.GetProperty(“Id”);
return this.SingleOrDefault(d => (int)idProperty.GetValue(d, null) == (int)keyValues.Single());
}
catch (ArgumentNullException ex)
{
throw new NotImplementedException(“Could not find a primary key by the name of ‘Id’. Derive from FakeDbSet and override Find.”);
}
}

Hi,I am very intrigued by your post,does it mean that the creation of Generic repository and Unitofwork is redundant,since we can mock the Repository using IDBSet? I would be grateful for a reply to my email in case I cannot find this post anymore

Here’s the latest version based on EF4.1

class FakeDbSet : IDbSet where T : class
{
readonly HashSet _data;
readonly IQueryable _query;

public FakeDbSet()
{
_data = new HashSet();
_query = _data.AsQueryable();
}

public T Add(T entity)
{
_data.Add(entity);
return entity;
}

public T Remove(T entity)
{
_data.Remove(entity);
return entity;
}

public T Attach(T entity)
{
_data.Add(entity);
return entity;
}

public TDerivedEntity Create() where TDerivedEntity : class, T
{
return Activator.CreateInstance();
}

public T Create()
{
return Activator.CreateInstance();
}

public T Find(params object[] keyValues)
{
throw new NotImplementedException(“Derive from FakeDbSet and override Find”);
}

public ObservableCollection Local
{
get { return new ObservableCollection(_data); }
}

public IEnumerator GetEnumerator()
{
return _data.GetEnumerator();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}

public Type ElementType
{
get { return _query.ElementType; }
}

public System.Linq.Expressions.Expression Expression
{
get { return _query.Expression; }
}

public IQueryProvider Provider
{
get { return _query.Provider; }
}
}

Somehow I had garbage in the buffer…here’s the correct EF4.1 version:

class FakeDbSet : IDbSet where T : class
{
readonly HashSet _data;
readonly IQueryable _query;

public FakeDbSet()
{
_data = new HashSet();
_query = _data.AsQueryable();
}

public T Add(T entity)
{
_data.Add(entity);
return entity;
}

public T Remove(T entity)
{
_data.Remove(entity);
return entity;
}

public T Attach(T entity)
{
_data.Add(entity);
return entity;
}

public TDerivedEntity Create() where TDerivedEntity : class, T
{
return Activator.CreateInstance();
}

public T Create()
{
return Activator.CreateInstance();
}

public T Find(params object[] keyValues)
{
throw new NotImplementedException(“Derive from FakeDbSet and override Find”);
}

public ObservableCollection Local
{
get { return new ObservableCollection(_data); }
}

public IEnumerator GetEnumerator()
{
return _data.GetEnumerator();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}

public Type ElementType
{
get { return _query.ElementType; }
}

public System.Linq.Expressions.Expression Expression
{
get { return _query.Expression; }
}

public IQueryProvider Provider
{
get { return _query.Provider; }
}
}

I have build similar classes with few improvements:

- use of IHasKey interface for every BO, and has primary key for every BO as int Id – and we have generic Find method

public class Client : IHasId
{
[Key]
public int Id { get; set; } // from Interface
….
}

public T Find(params object[] keyValues)
{
foreach (var keyValue in keyValues)
{
var res = _context.FirstOrDefault(k => k.Id == (int)keyValue);
if (res != null)
return res;
}
return null;
}

- also we have simulated SaveChanges

public class FakeDataSet : IDbSet where T : class, IHasId
{
private List _context = new List();
private List _toAdd = new List();
private List _toRemove = new List();
private List _toAttach = new List();

public int Save() { ….. }

}

and

public class FakeDataContext
{
public int SaveChanges()
{
var countChanges = 0;
var properties = ReflectionHelper.GetPropertiesOfType(GetType(), typeof(IDbSet));

foreach (var propName in properties)
{
var ds = ReflectionHelper.GetFieldOrProperty(this, propName);
countChanges += (int)ReflectionHelper.RaiseMethod(ds, “Save”);
}
return countChanges;
}

}

I have still one problem – how to count changes if we add tree of BO into FakeContext.

There is a way to generically implement Find by passing a function to be executed in the constructor:

Func _findFunction;

public FakeDbSet(Func findFunction)
{
_findFunction = findFunction;
_data = new HashSet();
_query = Data.AsQueryable();
}

public virtual T Find(params object[] keyValues)
{
return _findFunction.Invoke(keyValues);
}

Using your example, it can be used like this:

public class FakeEmployeeContext : IEmployeeContext
{
public FakeEmployeeContext()
{
this.Departments = new FakeDbSet(kv => this.Departments.SingleOrDefault(d => d.DepartmentId == (int)kv.Single()));
this.Employees = new FakeDbSet(kv => this.Employees.SingleOrDefault(d => d.EmployeeId == (int)kv.Single()));
}

public IDbSet Departments { get; private set; }

public IDbSet Employees { get; private set; }

public int SaveChanges()
{ return 0; }
}

Now there is no need to create a child class for each FakeDbSet.

I took a different approach:

public T Find(params object[] keyValues)
{
var finders = new Dictionary<Type, Func> {
{typeof(LookupTableType), x => x.LookupTableTypeID == (int)keyValues.First()},
{typeof(ApplicationSetting), x => x.Key == (string)keyValues.First()}
};

if( finders.ContainsKey(typeof(T)))
return _queryableSet.SingleOrDefault(finders[typeof (T)]);

throw new NotImplementedException(“Find method not implemented for type”);
}

All,

Here is the easiest way I’ve found to implement the finders:

public class Repository
{

public virtual IEnumerable Find(Expression<Func> whereClause)
{
return _dbSet.Where(whereClause).ToArray();
}

}

Usage:

var people = new Repository();
people.Find(p => p.Id == 1);

Trying again with generics encoded: Hope this works better :)

public class Repository<TEntity>
{

public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> whereClause)
{
return _dbSet.Where(whereClause).ToArray();
}

}

Usage:

var people = new Repository<Person>();
people.Find(p => p.Id == 1);

If using DataAnnotations I’ve found a nice way to implement find.
Find Method:

private List _keyProperties;

public virtual T Find(params object[] keyValues)
{
if (keyValues.Length != _keyProperties.Count)
throw new ArgumentException(“Incorrect number of keys passed to find method”);

IQueryable keyQuery = this.AsQueryable();
for (int i = 0; i _keyProperties[x].GetValue(entity, null).Equals(keyValues[x]));
}

return keyQuery.Single();
}

private void GetKeyProperties()
{
_keyProperties = new List();
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (PropertyInfo property in properties)
{
foreach (Attribute attribute in property.GetCustomAttributes(true))
{
if (attribute is KeyAttribute)
{
_keyProperties.Add(property);
}
}
}
}

Helpful Post. Thanks!

Thank you for the implementation in the comments. I have created a gist that add back the that were filtered out. Hope it saves somebody some time :)

https://gist.github.com/1438893

[...] If you want to do unit testing with Entity Framework 4.2, I suggest you read this article: http://romiller.com/2010/09/07/ef-ctp4-tips-tricks-testing-with-fake-dbcontext/ [...]

Great, thanks for posting this. it helped out more than you would know.
JR

Rowan,

You say that a dependency on EF can be removed by using IDbSet, but IDbSet is defined by EF. Is it still possible to remove the hard dependency on EF5, or do I have to add it to all of my projects?

Thanks,
Ryan

Hi ,
I think this would work for Code first approach,May I know how can I do this for database first approach,
Autogenerated class inherited from ObjectContext instead from DbCOntext.


Where's The Comment Form?

    About

    Rowan works as a Program Manager for the ADO.NET Entity Framework team at Microsoft. He speaks at technical conferences and blogs at romiller.com. Rowan lives in Seattle, Washington with his wife Athalie. Prior to moving to the US he resided in the small state of Tasmania in Australia. Outside of technology Rowan's passions include snowboarding, mountain biking, horse riding, rock climbing and pretty much anything else that involves being active. The primary focus of his life, however, is to follow Jesus.

    RSS

    Subscribe Via RSS

    • Subscribe with Bloglines
    • Add your feed to Newsburst from CNET News.com
    • Subscribe in Google Reader
    • Add to My Yahoo!
    • Subscribe in NewsGator Online
    • The latest comments to all posts in RSS

    Meta

Liked it here?
Why not try sites on the blogroll...

Follow

Get every new post delivered to your Inbox.

Join 159 other followers

%d bloggers like this: