Unit Tests in Controller mocking EF Context

Asked

Viewed 874 times

1

I’m not getting a solution on how to test my application (mocking the EF context)

EF context:

public class SawluxContexto : DbContext
    {
        public DbSet<Restaurante> Restaurante { get; set; }
        public DbSet<Prato> Prato { get; set; }

        public SawluxContexto()
            : base("Sawlux")
        {
            Database.SetInitializer<SawluxContexto>(null);
        }
}

Repositoriobase:

public abstract class RepositorioBase<TEntity> : IDisposable, IRepositorio<TEntity> where TEntity : class
    {
        protected SawluxContexto ctx;

        public RepositorioBase(SawluxContexto repo)
        {
            ctx = repo;
        }

        public IQueryable<TEntity> GetAll()
        {
            return ctx.Set<TEntity>();
        }

        public IQueryable<TEntity> Get(Func<TEntity, bool> predicate)
        {
            return GetAll().Where(predicate).AsQueryable();
        }

        public IQueryable<TEntity> Get(Func<TEntity, bool> predicate, string[] includes)
        {
            var query = GetAll().Where(predicate).AsQueryable();
            foreach (var include in includes)
            {
                query = query.Include(include);
            }
            return query;
        }

        public TEntity Find(params object[] key)
        {
            return ctx.Set<TEntity>().Find(key);
        }

        public void Update(TEntity obj)
        {
            ctx.Entry<TEntity>(obj).State = EntityState.Modified;
        }

        public void Save()
        {
            ctx.SaveChanges();
        }

        public void Add(TEntity obj)
        {
            ctx.Set<TEntity>().Add(obj);
        }

        public void Add(List<TEntity> obj)
        {
            ctx.Configuration.AutoDetectChangesEnabled = false;
            ctx.Set<TEntity>().AddRange(obj);
            ctx.ChangeTracker.DetectChanges();
        }

        public void Delete(Func<TEntity, bool> predicate)
        {
            ctx.Set<TEntity>()
                .Where(predicate).ToList()
                .ForEach(del => ctx.Set<TEntity>().Remove(del));
        }

        public void Dispose()
        {
            ctx.Dispose();
        }
    }

Repository:

public class RestauranteRepositorio : RepositorioBase<Restaurante>
{
    public RestauranteRepositorio(SawluxContexto repo)
        : base(repo)
    {
    }
}

Servicebase:

public abstract class ServiceBase<TEntity> : IDisposable, IRepositorio<TEntity> where TEntity : class
{
    protected RepositorioBase<TEntity> repository;

    public ServiceBase(RepositorioBase<TEntity> repository)
    {
        this.repository = repository;
    }

    public IQueryable<TEntity> GetAll()
    {
        return repository.GetAll();
    }

    public IQueryable<TEntity> Get(Func<TEntity, bool> predicate)
    {
        return repository.Get(predicate);
    }

    public IQueryable<TEntity> Get(Func<TEntity, bool> predicate, string[] includes)
    {
        return repository.Get(predicate, includes);
    }

    public TEntity Find(params object[] key)
    {
        return repository.Find(key);
    }

    public void Update(TEntity obj)
    {
        repository.Update(obj);
    }

    public void Save()
    {
        repository.Save();
    }

    public void Add(TEntity obj)
    {
        repository.Add(obj);
    }

    public void Add(List<TEntity> obj)
    {
        repository.Add(obj);
    }

    public void Delete(Func<TEntity, bool> predicate)
    {
        repository.Delete(predicate);
    }

    public void Dispose()
    {
        repository.Dispose();
    }
}

Service:

public class RestauranteService : ServiceBase<Restaurante>
{
    public RestauranteService(SawluxContexto repo)
        : base(new RestauranteRepositorio(repo))
    {
    }
}

And finally my controller:

public class RestauranteController : Controller
{
    readonly SawluxContexto contexto;
    readonly RestauranteService restauranteService;

    public RestauranteController()
    {
        contexto = new SawluxContexto();
        restauranteService = new RestauranteService(contexto);
    }
    // GET: Restaurante
    public ActionResult Index(string restaurante)
    {
        var restaurantes = new List<Restaurante>();
        if (!string.IsNullOrEmpty(restaurante))
            restaurantes = restauranteService.Get(x => x.Nome.ToLower().Contains(restaurante.ToLower())).ToList();
        else
            restaurantes = restauranteService.GetAll().ToList();

        var restaurantesVM = new List<RestauranteVM>();
        foreach (var restauranteModel in restaurantes)
        {
            restaurantesVM.Add(new RestauranteVM
            {
                Nome = restauranteModel.Nome,
                Id = restauranteModel.Id
            });
        }
        return View(restaurantesVM);
    }

    public ActionResult Cadastro(int id = 0)
    {
        var restaurante = new Restaurante();
        if (id > 0)
            restaurante = restauranteService.Get(x => x.Id == id).FirstOrDefault();

        var restauranteVM = new RestauranteVM { Nome = restaurante.Nome, Id = restaurante.Id };
        return View(restauranteVM);
    }

    [HttpPost]
    public ActionResult Cadastro(RestauranteVM restauranteVM)
    {
        if (ModelState.IsValid)
        {
            var restaurante = new Restaurante();
            if (restauranteVM.Id > 0)
                restaurante = restauranteService.Get(x => x.Id == restauranteVM.Id).FirstOrDefault();

            restaurante.Nome = restauranteVM.Nome;

            if (restauranteVM.Id > 0)
                restauranteService.Update(restaurante);
            else
                restauranteService.Add(restaurante);

            restauranteService.Save();
            return RedirectToAction("Index");
        }
        return View(restauranteVM);
    }

    public ActionResult Delete(int id)
    {
        restauranteService.Delete(x => x.Id == id);
        restauranteService.Save();
        return RedirectToAction("Index");
    }
}

I don’t know if my approach to testing is right. But I would like to test in Servicebase and Controller. But I can’t think of a way to do this.

1 answer

0

I’ve recently studied some references to create better unit tests. If you have not yet accessed this material: https://docs.microsoft.com/pt-br/dotnet/core/testing/? view=aspnetcore-2.0, leave here.

Unit tests are performed with a very direct goal. In the example of a Controller, test the logic of the controller itself. Filters, repositories and others should not be part of the test. To test the behavior of a service running on a controller, the test is integration and non-unitary.

It’s worth searching over TDD for you to continue building your app with testing.

I believe this material will help you:

Unit test: https://docs.microsoft.com/pt-br/dotnet/core/testing/unit-testing-with-dotnet-test?view=aspnetcore-2.0

Controller Test: https://docs.microsoft.com/pt-br/aspnet/core/mvc/controllers/testing?view=aspnetcore-2.0

Integration test: https://docs.microsoft.com/pt-br/aspnet/core/testing/integration-testing?view=aspnetcore-2.0

  • The references are for Asp.net core, but the idea is the same.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.