Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with an IDisposable repository with Unity?

I have a job in which I have an IDisposable DbContext. I would like to unit test this job without hitting in a database. What options do i have to do this?

Im using the default Fakes assembly' of microsoft.

My job:

public void Work()
{
    do
    {   
        //code here                
        using (var repository = new Repository<User>())
        {
            repository.Save(user);
        }

    } while (true);
}

I'm trying to test and in this part of the test it fails because it actually creates a new instance of the Repository class.

My test Method:

using (ShimsContext.Create())
{
    Data.Repository.Fakes.ShimRepository<Domain.Fakes.ShimUser>.Constructor = (a) => { };

    Data.Repository.Fakes.ShimRepository<Domain.Fakes.ShimUser>.AllInstances.SaveT0 = (a, b) =>
    {
    };

   var service = GetService();
    service.Work(); //Throws exception
}

How can I fake this Save method?

like image 977
gog Avatar asked Oct 15 '15 13:10

gog


2 Answers

You've violated DIP here, making unit testing your service far more difficult than it should be. You should also avoid generic repositories and favour role interfaces.

Instead, inject an abstraction into your service of your repository, e.g. IUsersRepository which defines your Save method. Then in your unit test of the service you can simply use a stub implementation of IUsersRepository.

like image 113
devdigital Avatar answered Nov 14 '22 23:11

devdigital


Fakes tend to reveal that your code is not properly following the D in SOLID since you are creating dependencies inside your class instead of passing them in.

A much better pattern would to create an ISaveRepository interface that in turn implements IDisposable with an exposed Save() method. You should then inject an instance of your repository into your class. This will allow you to satisfy the using statement testing, as well as implement a mock that defines a .Save() method that does not hit the database.

public class Test
{
    private readonly ISaveRepository _userRepository;

    public Test(ISaveRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public void Work()
    {
        using (_userRepository)
        {
            var cont = true;
            do
            {              
                _userRepository.Save(new User());
                cont = false;
            } while (cont);
        } 
    }
}

public interface ISaveRepository : IDisposable
{
    void Save<T>(T model);
}

public class Repository<T> : ISaveRepository
{
    public void Dispose() { }
    public void Save<TT>(TT model) {}
}

public class User {}
like image 25
David L Avatar answered Nov 14 '22 22:11

David L