Introducing Effort

So what is Effort? It stands for Entity Framework Fake ObjectContext Realization Tool. Basically this is exactly what it is meant to do. Creating automated tests for data driven applications has never been a trivial task. This is also true for Entity Framework based applications, implementing proper fake ObjectContext or DbContext class requires great effort. Oh, sure… 🙂

This library approaches this problem from a very different way, it tries to emulate the underlying resource-heavy external database with a lightweight in-process in-memory database. This makes possible to run your tests rapidly without the presence of an external database. At the end of this blog post, you will see exactly how.

Effort can be downloaded from Codeplex or installed with NuGet. It is really convenient to use, practically you don’t have to do any modification to your existing ObjectContext or DbContext classes. This is presented by the following example. Let’s assume that we have an ObjectContext class called NorthwindEntities.

using(NorthwindEntities context = new NorthwindEntities())
{
    return context.Categories.ToList();
}

This code returns all the categories stored in the database. A simple modification is enough to make Entity Framework use a fake in-memory database instead:

using(NorthwindEntities context = 
    Effort.ObjectContextFactory.CreateTransient<NorthwindEntities>())
{
    return context.Categories.ToList();
}

The term “transient” refers to the lifecycle of the underlying in-memory database. The owner ObjectContext (technically the DbConnection) will be using a completely unique database instance. If the context/connection is disposed, than the database will be disposed too. If you run this code, an empty collection will be returned. This is self-evident, since the fake database was completely empty.

You could set the initial state of the database with Entity Framework, but Effort provides data loaders to do this more easily. The following example fetches the initial data from a real database:

IDataLoader loader = new EntityDataLoader("name=NorthwindEntities");

using(NorthwindEntities context = 
    ObjectContextFactory.CreateTransient<NorthwindEntities>(loader))
{
    return context.Categories.ToList();
}

This and the first code will return exactly the same collection of entities, but there is a very big difference: you can do anything you want with this data context, the result will be the same all the time. The following example proves this:

IDataLoader loader = new EntityDataLoader("name=NorthwindEntities");

using(NorthwindEntities context = 
    ObjectContextFactory.CreateTransient<NorthwindEntities>(loader))
{
    foreach (Category cat in context.Categories)
    {
        context.Categories.DeleteObject(cat);
    }
    context.SaveChanges();
}

using(NorthwindEntities context = 
    ObjectContextFactory.CreateTransient<NorthwindEntities>(loader))
{
    return context.Categories.ToList();
}

The first part of this code deletes all the categories from the database. No matter, the second part of the code will return the exact same collection like before. If you run the code again, the first part has to delete the entities again, the object set will never be empty.

Furthermore, you can completely dismiss the need of the external database. Export your data tables into local CSV files (Effort provides a tool to do it easily) and use the CSV data loader.

IDataLoader loader = new CsvDataLoader("C:\PathOfTheCsvFiles");

using(NorthwindEntities context = 
    ObjectContextFactory.CreateTransient<NorthwindEntities>(loader))
{
    return context.Categories.ToList();
}

If you run this code, there will be zero communication with the external database, but it just behaves exactly like it had.

As you can see, Effort makes possible to create automated tests for Entity Framework applications in a very convenient and powerful way. The tests can run without the presence of any external database engine. Each test can work on a completely unique database instance, so their actions will be completely isolated, they can even run concurrently. The state of database they are working on can be easily initialized too.

Future posts will reveal the capabilities of Effort for different scenarios.

Advertisements

15 Responses to Introducing Effort

  1. stephan says:

    I have an edmx file generated (database first) with a DbContext (EF5) t4 template. All configuration and mappings reside in the edmx file. I want to use Effort, but now I get errors such as no key is defined on a table. I don’t want to re-configure all the entities (as in code first). This means I want to use the edmx file with effort.

    e.g. \tSystem.Data.Entity.Edm.EdmEntityType: : EntityType has no key defined. Define the key for this EntityType.
    I don’t have a choice regarding the column names (legacy database). I can not end the primary keys with Id.

    Is this possible and how?

    • tflamich says:

      Hello,
      What type of exception do you get? I assume this exception comes directly from Entity Framework, not Effort. Probably the T4 template does not generate the appropriate xml that should define the key.

      By the way you can use Effort with your DbContext class too.

      • stephan says:

        I do the following:
        DbConnection connection = Effort.DbConnectionFactory.CreateTransient();
        var context = new RepoUowEntitiesContext(connection);
        context.References.Add(new Reference{ @ref = 1, Value = “TEST”});

        With the last line (notice how the primary key is named ref by purpose instead of Id).

        ModelValidationException was unhandled by user code.
        \tSystem.Data.Entity.Edm.EdmEntityType: : EntityType ‘Reference’ has no key defined. Define the key for this EntityType.

        So I guess the schema is not being picked up (probably logic) and so it behaves as a code first model and expects keys to be configured. But I don’t want to do this. I want to use the information present in the edmx.

      • tflamich says:

        Does this work if you use SqlConnection? Did you annotate the ref property with a [Key] attribute?

      • stephan says:

        If I do:
        DbConnection connection = Effort.EntityConnectionFactory.CreateTransient(“name=RepoUowEntitiesContext”) I get other errors which are also schema defined.
        RepoUowEntitiesContext is a real connectionstring pointing to the edmx & db.

        Schema specified is not valid. Errors:

        (0,0) : error 0040: The Type int is not qualified with a namespace or alias. Only primitive types can be used without qualification.

        (0,0) : error 0040: The Type varchar is not qualified with a namespace or alia

      • stephan says:

        No it is not annoted with a Key. But the edmx defines this:

        The problem is that I already have a generated model based on an edmx.
        Is there any way to use the settings defined in the edmx.

        Because it will start out with simple keys, but after a while there will be other things to re-configure.
        It concerns a legacy database with hundreds of tables.

      • stephan says:

        This is the edmx configuration:

        <EntityType Name=”Reference”>
        <Key>
        <PropertyRef Name=”ref” />
        </Key>
        <Property Type=”Int16″ Name=”ref” Nullable=”false” />

      • tflamich says:

        The DbContext throws exception surely because there is no key defined in the entity. ModelValidationException is thrown before the Effort library could do anything. Use the [Key] attribute or override the OnModelCreating method of your DbContext class (and add code like “modelBuilder.Entity().HasKey(r => r.@ref)”).

        I need more info about the edmx to find out what is the other problem.

        Might I ask you send me private email?

      • stephan says:

        Do you have my email? I need to enter it with each comment post.
        Is there a way to get the settings (such as keys) from the edmx instead of having to redefine these settings in the OnModelCreating method?

      • tflamich says:

        I found it. Sent you an email.

  2. And I thought it stood for “Entity Framework FORTification” (T not N)… Strengthening the Entity Framework. I’ve only had a cursory look, but the big challenge is, “How to I test EF code on a build machine?” I hope to find the answer here.

    • tflamich says:

      Haha, that would be a nice acronym too.

      I haven’t tested this library on a build server yet, but since it runs completely within the boundaries of CLR, I don’t think there is any obstacle in doing that.

  3. Pingback: How do I mimic the functionality of IQueryable<T>.Include(Expression<Func<T,TProperty>> path) in my custom collection? | Ngoding

  4. Andreas says:

    I just stumbled over Effort and find it very interesting. However, I do have trouble to get it to work. I do not have any *.edmx file available, actually I never had to generate one to get my DbContext up and running. I have the impression that the edmx file is required for Effort to work. Is that right? Do I have any chance to use Effort without having an edmx?

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: