YAGNI - 'Poor-mans CQRS' sample application with Entity Framework

 
11/6/2011
.NET, C#, EF, Test
2 Comments

This week Daniel Lang published an interesting article about unnecessary overhead in simple applications.
In a nutshell he proposes an architecture called "Poor-mans CQRS". In his sample he uses an ASP.NET MVC application. The controllers retrieve their required data directly from the database (Query), and updates are performed in service layer (Command).
In this post I will provide a (simple) application, which is based on the Entity Framework. It shows the principle and explains how unit tests can be written without querying a real database.

Background

Many applications use a combination of the Repository- and UnitOfWorkPattern for accessing and modifying data. That makes sense for the following reasons:

  • It avoids duplicated data access code, especially if several front ends are involved
  • It enables testability, since mocking the ORM layer is/was not that easy
  • Enables you to replace your ORM mapper (at least in theory...)

But there are several drawbacks. In case that your application has only one front end, development could be much faster when accessing the database directly (look at Daniel's article for details). Why add some extra layer of abstraction, if your ORM already provides a UnitOfWork? Repositories are already available in your DataContext!
Another advantage is, that you could write optimized queries against your favorite ORM and use its special features.
Loosing the ability to replace the ORM is not a big issue, since this is not very likely anyway.

Example

Now let's have a look at a sample application, which is using the Entity Framework. Testability has been improved in version 4.0. It not very difficult to write tests without a real database.

In my application I use a single Entity called TestEntity. The frontend has two views, one view to show all TestEntities and another view to edit one TestEntity.

The following DbContext is used:

public class Context : DbContext
{
    public Context()
    {
    }
public Context(string connectionString)
    : base(connectionString)
{
}

public virtual IDbSet<TestEntity> Tests { get; set; }

}

The context is used directly to access the data in my controller:

public class HomeController : Controller
{
    private readonly Context context;

    public HomeController(Context context)
    {
        this.context = context;
    }

    public ActionResult Index()
    {
        // Use the DBContext for querying data, no service and no repository involved here
        var model = this.context.Tests.OrderBy(t => t.Name).ToArray();
        return View(model);
    }
}

Now let's have a look at the corresponding test.
The DbContext exposes a property of type IDbSet for my TestEntities. In order to run the test without accessing a real database, I use a implementation of IDbSet that holds its data in memory (see this article for more details).
First I create two instances of my entities and then I instantiate the MemoryDbSet. After setting up the DbContext, the tests could be executed:

private IEnumerable<TestEntity> testEntities;

private Context context;

[TestInitialize]
public void Setup()
{
    this.testEntities = new[] 
    {
        new TestEntity()
        {
            Id = Guid.NewGuid(),
            Name = "Test2"
        },
        new TestEntity()
        {
            Id = Guid.NewGuid(),
            Name = "Test1"
        }
    };
    this.context = new Context()
    {
        Tests = new MemoryDbSet<TestEntity>(this.testEntities)
    };
}

[TestMethod]
public void Index()
{
    // Arrange
    HomeController controller = new HomeController(this.context);

    // Act
    ViewResult result = controller.Index() as ViewResult;

    // Assert
    Assert.IsInstanceOfType(result.Model, typeof(IEnumerable<TestEntity>));
    Assert.AreEqual(this.testEntities.Count(), ((IEnumerable<TestEntity>)result.Model).Count());
}

With Entity Framework 6 you don't have to implement MemoryDbSet yourself. You can use a mocking framework as described in this article.

Conclusion

Depending on your overall requirements, it's often enough to use a simple approach for accessing a database. It helps you to speed up development without loosing the ability to write unit tests. And testing is not that much effort, no need to setup a lot of mocks for a simple test!

Downloads

Feedly Feedly Tweet


Related posts


Comments


Mario Blasius

Mario Blasius

1/10/2016

Was hat das Beispiel mit CQRS zu tun? Gruß Mario


Mathew Vance

Mathew Vance

11/15/2011

Hi Daniel, Thanks for putting me on to Scott's whitepaper and this great example. I've been trying to simplify my smaller MVC projects and migrate to EF from linqtosql at the same time. I'm now up and running with InMemoryObjectSet in my tests. Clean and simple. Thanks again, Mathew