How to test an Asp.net mvc controler using Moq and Entity Framework 6

Asked

Viewed 233 times

5

My controller:

[Authorize]
    public class DominioController : Controller
    {

        private IDominioDB _db;

        public DominioController(IDominioDB db)
        {
            _db = db;
        }

        // GET: Dominio
        public async Task<ActionResult> Index()
        {

            var userID = User.Identity.GetUserId();
            var d = await _db.Dominios.Where(x => x.idUsu == userID).ToListAsync();

            ViewBag.Username = User.Identity.Name;

            return View(d);
        }
    }

My method of testing:

[TestMethod]
        public async Task VERIFICA_CONTROLE_DOMINIO()
        {

            var data = new List<DBDominio>()
            {
                new DBDominio() { idUsu = "usuario1" },
                new DBDominio() { idUsu = "usuario2" },new DBDominio() { idUsu = "usuario2" },
                new DBDominio() { idUsu = "usuario3" },new DBDominio() { idUsu = "usuario3" }
            }.AsQueryable();

            var mockSet = new Mock<DbSet<DBDominio>>();


            mockSet.As<IDbAsyncEnumerable<DBDominio>>()
                .Setup(m => m.GetAsyncEnumerator())
                .Returns(new TestDbAsyncEnumerator<DBDominio>(data.GetEnumerator()));

            mockSet.As<IQueryable<DBDominio>>()
                .Setup(m => m.Provider)
                .Returns(new TestDbAsyncQueryProvider<DBDominio>(data.Provider));


            mockSet.As<IQueryable<DBDominio>>().Setup(m => m.Expression).Returns(data.Expression);
            mockSet.As<IQueryable<DBDominio>>().Setup(m => m.ElementType).Returns(data.ElementType);
            mockSet.As<IQueryable<DBDominio>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

            var repo = new Mock<Interfaces.IDominioDB>();
            repo.Setup(c => c.Dominios).Returns(mockSet.Object);


            var context = new Mock<ControllerContext>();
            var mockIdentity = new Mock<IIdentity>();
            context.SetupGet(x => x.HttpContext.User.Identity).Returns(mockIdentity.Object);
            mockIdentity.Setup(x => x.Name).Returns("usuario1");



            // Arrange
            DominioController controller = new DominioController(repo.Object)
            {
                ControllerContext = context.Object
            };

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

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(result.ViewBag.Username , "usuario1");

        }

I want to know how I could check if the var d = await _db.Dominios.Where(x => x.idUsu == userID).ToListAsync(); that is within the controler returns the right amount of records, this is possible this way?

I know I could create a Service layer between the controller and EF, what I don’t like this solution is that in some time there are 200 different methods within a service and start giving me maintenance problems.

  • See if this helps. If it doesn’t help, I’ll write one more answer.

  • I liked your solution, but with it, how would you know how many records would return on my line? var d = await _db.Dominios.Where(x => x.idUsu == userID).ToListAsync();

  • It depends on the organization of your Mock. The advantage of my proposal in relation to Moq is that you effectively test with data, even if invented. Therefore, the counts are known to you.

  • So it’s this mock organization that made me ask the question :)

  • If you like, I can expand that answer into a more specialized context for you. What do you think?

  • 1

    I think great, actually I already implemented your answer in the code, I just didn’t close the question because I still don’t understand how I could test that part of the code I put in the question, but my code is already using your solution.

  • Okay, I’ll write you that tomorrow.

Show 2 more comments

1 answer

2


I didn’t have to mockar nothing to get the result I wanted. I just took the amount that was already in the result and I didn’t know.

(That’s beside the point) I put a different way of mocking the Indetify.

In return I take the result.Model.

Follow the control and test code:

Controller:

[Authorize]
    public class DominioController : Controller
    {

        private IDominioDB _db;

        public DominioController(IDominioDB db)
        {
            _db = db;
        }

        // GET: Dominio
        public async Task<ViewResult> Index()
        {

            var userID = User.Identity.GetUserId();
            var d = await _db.Dominios.Where(x => x.idUsu == userID).ToListAsync();

            ViewBag.Username = User.Identity.Name;

            return View(d);
        }
    }

Test:

[TestMethod]
        public async Task VERIFICA_CONTROLE_DOMINIO()
        {

            //CRIANDO GENERICINDENTITY 
            string username = "Ricardo";
            string userid = "usuario1"; 

            List<Claim> claims = new List<Claim>{
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", username),
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", userid)
            };
            var genericIdentity = new GenericIdentity(username);
            genericIdentity.AddClaims(claims);

            var genericPrincipal = new GenericPrincipal(genericIdentity, new string[] { "Ricardo" });
            //*************************


            //CRIANDO BASE DE DADOS PARA TESTE E FAZENDO O MOCK DO CONTEXTO
            var data = new List<DBDominio>()
            {
                new DBDominio() { idUsu = "usuario1" },
                new DBDominio() { idUsu = "usuario2" },new DBDominio() { idUsu = "usuario2" },
                new DBDominio() { idUsu = "usuario3" },new DBDominio() { idUsu = "usuario3" }
            }.AsQueryable();

            var mockSet = new Mock<DbSet<DBDominio>>();
            //*************************


            mockSet.As<IDbAsyncEnumerable<DBDominio>>()
                .Setup(m => m.GetAsyncEnumerator())
                .Returns(new TestDbAsyncEnumerator<DBDominio>(data.GetEnumerator()));

            mockSet.As<IQueryable<DBDominio>>()
                .Setup(m => m.Provider)
                .Returns(new TestDbAsyncQueryProvider<DBDominio>(data.Provider));


            mockSet.As<IQueryable<DBDominio>>().Setup(m => m.Expression).Returns(data.Expression);
            mockSet.As<IQueryable<DBDominio>>().Setup(m => m.ElementType).Returns(data.ElementType);
            mockSet.As<IQueryable<DBDominio>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

            var repo = new Mock<Interfaces.IDominioDB>();
            repo.Setup(c => c.Dominios).Returns(mockSet.Object);


            //AQUI AO CRIAR O MOCK DE CONTROLLER EU FAÇO O SETUP COLOCANDO O IDENTITY PARA RETORNAR O GENERICIDENTITY CRIADO ACIMA
            var context = new Mock<ControllerContext>();
            context.SetupGet(x => x.HttpContext.User.Identity).Returns(genericIdentity);


            //AO CRIAR O OBJETO CONTROLER EU PASSO O CONTEXTO COM O INDENTITY NELE.
            // Arrange
            DominioController controller = new DominioController(repo.Object)
            {
                ControllerContext = context.Object,

            };

            // Act
            ViewResult result = (ViewResult)await controller.Index();
            var resultModel = (IEnumerable<DBDominio>)result.Model;

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(result.ViewBag.Username , "Ricardo");
            Assert.AreEqual(resultModel.Count(), 1);

        }

Browser other questions tagged

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