Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock an object, that is instanciated in a using() block

When reading/writing to a context from Entity Framework I often read, that it is recommended to keep the context's lifecycle as short as possible (one context per unit of work). It makes a lot of sense to do that, however how am I supposed to write a unit test for a class that is creating and disposing this context in every method?

Let's see a simplified fictional example code snippet:

public class Resource : IResource {
    public Item GetItem(string name) {
        using(var context = new DbContext()) {
            return context.Items.FirstOrDefault(item => item.Name == name);
        }
    }
}

If I want to unit-test the Resource, I would like to mock the DbContext, so it returns some fake data for me.

My usual approach would be to make the DbContext a property of my class and inject it from outside like this:

public class Resource : IResource {
    public DbContext Context { private get; set; }

    public Item GetItem(string name) {
        return this.Context.Items.FirstOrDefault(item => item.Name == name);
    }
}

This way, the instanciating class which injects the context is responsible for the life-cycle and I can omit the using and I can inject a mocked context of course.

Now taking into consideration, that providing a long living context might be a bad idea and following the one context per unit of work principle, this option is not favourable.

So what options do I have? One idea is to inject a ContextFactory, which creates and disposes the context on demand like this:

public class Resource : IResource {
    public DbContextFactory ContextFactory { private get; set; }

    public Item GetItem(string name) {
        using(var context = ContextFactory.CreateContext()) {
            return context.Items.FirstOrDefault(item => item.Name == name);
        }
    }
}

Does this make sense or am I going into a completely wrong directon?

like image 297
Jan Avatar asked Sep 11 '25 15:09

Jan


2 Answers

The option is to use Method Injection:

   public Item GetItem(string name, DbContext context) {
        using(var context) {
            return context.Items.FirstOrDefault(item => item.Id == id);
        }
    }

Also Seemann in his book Dependency Injection in .Net uses this method to inject dependency which can change from call to call.

But I'd use ContextFactory.

like image 154
Anton Sizikov Avatar answered Sep 13 '25 04:09

Anton Sizikov


I checked out Mark Seemann's book (mentioned by Anton Sizikov) and he actually uses a factory as well, calling it an ephemeral disposable. It is somehow a Leaky Abstraction, because the factory manages the disposable dependency's life time instead of the DI container. Still it's better than having a memory leak due to undisposed disposables or exceptions caused by disposed shared dependencies.

like image 37
Jan Avatar answered Sep 13 '25 05:09

Jan