Search code examples
linqunit-testingnunitmoqrepository-pattern

Mocking an Anonymous type parameter in Dapper and Filtering result by parameter's property


I'm not very familiar with Moq and NUnit, that's why I'm struggling with this one. I'm using Dapper for my generic repository, and it's been injected into a service and, then, used to fulfil the logic. My problem is that I use it in a LinQ's Select passing a parameter from the previous Object. And I have no idea how to reflect that in the Mock...

This is my Service:

public class StudyService: IStudyService
    {
        private readonly ILogger<StudyService> _logger;
        private readonly IDataRepository _dataRepository;

        public StudyService(ILogger<StudyService> logger, IDataRepository dataRepository)
        {
            _logger = logger;
            _dataRepository = dataRepository;
        }
[...]
        // This is the method to test:
        public async Task<StudiesResponse> GetAllStudies()
        {
            StudiesResponse studies = new StudiesResponse();
            List<StudyReponse> list = new List<StudyReponse>();

            foreach (StudyDAO study in await _dataRepository.GetEntitiesAsync<StudyDAO>())
            {
                StudyReponse resp = new StudyReponse()
                {
                    StudyCode = study.StudyCode,
                    Participators = _dataRepository.GetEntitiesAsync<RoleUserDAO>(new { @StudyId = study.Id }).Result.Select(x => new ParticipatorsResponse()
                    {
                        UserEmail = _dataRepository.GetEntityAsync<UserDAO>(new { @Id = x.Id }).Result.Email,
                        RoleName = _dataRepository.GetEntityAsync<RoleDAO>(new { @Id = x.Id }).Result.Name
                    })
                };


                list.Add(resp);
            }

            studies.Studies = list;
            return studies;
        }
[...]
   }
}

As you can see the calls to retrieve UserEmail and RoleName are fed by the Select of the previous "_dataRepository.GetEntitiesAsync" This is what I don't have a clue how to mock...

This is my generic/anonymous repository:

   public class DataRepository : IDataRepository
    {
        private readonly IConfiguration _configuration;
       
        public DataRepository(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public async Task<IEnumerable<T>> GetEntitiesAsync<T>()
        {
            using(IDbConnection conn = new SqlConnection(_configuration.GetConnectionString("SqlConnection")))
            {
                return await conn.GetListAsync<T>();
            }   
        }
        public async Task<IEnumerable<T>> GetEntitiesAsync<T>(object query)
        {
            using (IDbConnection conn = new SqlConnection(_configuration.GetConnectionString("SqlConnection")))
            {
                return await conn.GetListAsync<T>(query);
            }
        }

        public async Task<T> GetEntityAsync<T>(object query)
        {
            using (IDbConnection conn = new SqlConnection(_configuration.GetConnectionString("SqlConnection")))
            {
                IEnumerable<T> result = await conn.GetListAsync<T>(query);
                return result.FirstOrDefault();
            }
        }
[...]

This is my test class:

[TestFixture]
    public class Tests
    {
        IEnumerable<StudyDAO> _studies;
        IEnumerable<UserDAO> _users;
        IEnumerable<RoleDAO> _roles;
        IEnumerable<RoleUserDAO> _roleUsers;

        
        [SetUp]
        public void Setup()
        {
            _studies = MockedDAOs.GetMockedStudies();
            _users = MockedDAOs.GetMockedUsers();
            _roles = MockedDAOs.GetMockedRoles();
            _roleUsers = MockedDAOs.GetMockedRoleUsers();
        }

        [Test]
        public void GetAllStudiesTest()
        {
            var _data = new Mock<IDataRepository>();
            _data.Setup(m => m.GetEntitiesAsync<StudyDAO>()).Returns(Task.FromResult(_studies));
            _data.Setup(m => m.GetEntitiesAsync<RoleUserDAO>(It.IsAny<Object>())).Returns(Task.FromResult(_roleUsers));
            _data.Setup(m => m.GetEntityAsync<UserDAO>(It.IsAny<Object>())).Returns(Task.FromResult(_users.Where(u => u.Id ==????)));
            _data.Setup(m => m.GetEntityAsync<RoleDAO>(It.IsAny<Object>())).Returns(Task.FromResult(_roles.Where(u => u.Id ==????)));

            var _logger = Mock.Of<ILogger<StudyService>>();
            StudyService _service = new StudyService(_logger, _data.Object);

            var result = _service.GetAllStudies();

            Assert.Pass();
        }
    }

And this is my "mocked" data constructors:

 public static class MockedDAOs
    {
        public static IEnumerable<UserDAO> GetMockedUsers()
        {
            List<UserDAO> users = new List<UserDAO>();
            users.Add(new UserDAO()
            {
                Id = 1,
                Email = "lordvaderr@galacticempire.com",
                Address = "Alderaan Sector 1234",
                LanguajePreference = "English",
                UpdateUser = "Admin"
            });
            users.Add(new UserDAO()
            {
                Id = 2,
                Email = "senatorpalpatine@galacticempire.com",
                Address = "Alderaan Sector 1233",
                LanguajePreference = "English",
                UpdateUser = "Admin"
            });
            users.Add(new UserDAO()
            {
                Id = 3,
                Email = "generalrommohc@galacticempire.com",
                Address = "Alderaan Sector 1232",
                LanguajePreference = "English",
                UpdateUser = "Admin"
            });
            users.Add(new UserDAO()
            {
                Id = 4,
                Email = "secenthsister@galacticempire.com",
                Address = "Alderaan Sector 1231",
                LanguajePreference = "English",
                UpdateUser = "Admin"
            });
            return users;
        }

        public static IEnumerable<StudyDAO> GetMockedStudies()
        {
            List<StudyDAO> studies = new List<StudyDAO>();
            studies.Add(new StudyDAO()
            {
                Id = 1,
                StudyCode = "order66",
                Company = "Galactic Empire",
                UpdateUser = "Admin"
            });

            return studies;
        }

        public static IEnumerable<RoleDAO> GetMockedRoles()
        {
            List<RoleDAO> roles = new List<RoleDAO>();
            roles.Add(new RoleDAO()
            {
                Id = 1,
                Name = "General Director",
                Curriculum = "Ruthless Management I",
                UpdateUser = "Admin"
            });
            roles.Add(new RoleDAO()
            {
                Id = 2,
                Name = "CEO",
                Curriculum = "Smoke and Mirrors I",
                UpdateUser = "Admin"
            });
            roles.Add(new RoleDAO()
            {
                Id = 3,
                Name = "Strategy Director",
                Curriculum = "Detecting Critical Targets",
                UpdateUser = "Admin"
            });
            roles.Add(new RoleDAO()
            {
                Id = 4,
                Name = "Deliver",
                Curriculum = "Silent Aproaches",
                UpdateUser = "Admin"
            });
            return roles;
        }

        public static IEnumerable<RoleUserDAO> GetMockedRoleUsers()
        {
            List<RoleUserDAO> roleUsers = new List<RoleUserDAO>();
            roleUsers.Add(new RoleUserDAO()
            {
                Id = 1,
                UserId = 1,
                RoleId = 1,
                StudyId = 1,
                UpdateUser = "Admin"
            });
            roleUsers.Add(new RoleUserDAO()
            {
                Id = 2,
                UserId = 2,
                RoleId = 2,
                StudyId = 1,
                UpdateUser = "Admin"
            });
            roleUsers.Add(new RoleUserDAO()
            {
                Id = 3,
                UserId = 3,
                RoleId = 3,
                StudyId = 1,
                UpdateUser = "Admin"
            });
            roleUsers.Add(new RoleUserDAO()
            {
                Id = 4,
                UserId = 4,
                RoleId = 4,
                StudyId = 1,
                UpdateUser = "Admin"
            });
            return roleUsers;
        }

        public static StudiesResponse GetMockedStudiesResponse()
        {
            List<ParticipatorsResponse> participatorsResponse = new List<ParticipatorsResponse>();
            participatorsResponse.Add(new ParticipatorsResponse(){
                UserEmail = "lordvaderr@galacticempire.com",
                RoleName = "General Director"
            });
            participatorsResponse.Add(new ParticipatorsResponse()
            {
                UserEmail = "senatorpalpatine@galacticempire.com",
                RoleName = "CEO"
            });
            participatorsResponse.Add(new ParticipatorsResponse()
            {
                UserEmail = "generalrommohc@galacticempire.com",
                RoleName = "Strategy Director"
            });
            participatorsResponse.Add(new ParticipatorsResponse()
            {
                UserEmail = "secenthsister@galacticempire.com",
                RoleName = "Deliver"
            });

            List<StudyReponse> studyResponse = new List<StudyReponse>();
            studyResponse.Add(new StudyReponse()
            {
                StudyCode = "order66",
                Participators = participatorsResponse
            });

            return new StudiesResponse()
            {
                Studies = studyResponse
            };
        }
    }

I'm out of ideas and I can't find any example with a scenario like this...

EDIT: Ok, I found a post with something that I thought can be used:

Test:

        [Test]
        public void GetAllStudiesTest()
        {
            var _data = new Mock<IDataRepository>();
            _data.Setup(m => m.GetEntitiesAsync<StudyDAO>()).Returns(Task.FromResult(_studies));
            _data.Setup(m => m.GetEntitiesAsync<RoleUserDAO>(It.IsAny<Object>())).ReturnsAsync((Object obj) => _roleUsers.Where(x => x.Id == obj.Id));
            _data.Setup(m => m.GetEntityAsync<UserDAO>(It.IsAny<Object>())).ReturnsAsync((Object obj) => _users.Where(x => x.Id == obj.Id).FirstOrDefault());
            _data.Setup(m => m.GetEntityAsync<RoleDAO>(It.IsAny<Object>())).ReturnsAsync((Object obj) => _roles.Where(x => x.Id == obj.Id).FirstOrDefault());

            var _logger = Mock.Of<ILogger<StudyService>>();
            StudyService _service = new StudyService(_logger, _data.Object);

            var result = _service.GetAllStudies();

            Assert.True(comparator.Compare(result, MockedDAOs.GetMockedStudiesResponse()).AreEqual); 
        }

But it's not working. With this code, the first call to recover the IEnumerable returns 0 results... I'll keep looking. Any help will be appreciated.


Solution

  • I managed to solve the issue. The correct code for the Test is:

            [Test]
            public void GetAllStudiesTest()
            {
                var _data = new Mock<IDataRepository>();
                _data.Setup(m => m.GetEntitiesAsync<StudyDAO>()).Returns(Task.FromResult(_studies));
                _data.Setup(m => m.GetEntitiesAsync<RoleUserDAO>(It.IsAny<Object>())).ReturnsAsync((Object obj) => _roleUsers.Where(x => x.StudyId == (int)obj.GetType().GetProperty("StudyId").GetValue(obj, null)));
                _data.Setup(m => m.GetEntityAsync<UserDAO>(It.IsAny<Object>())).ReturnsAsync((Object obj) => _users.Where(x => x.Id == (int)obj.GetType().GetProperty("Id").GetValue(obj, null)).FirstOrDefault());
                _data.Setup(m => m.GetEntityAsync<RoleDAO>(It.IsAny<Object>())).ReturnsAsync((Object obj) => _roles.Where(x => x.Id == (int)obj.GetType().GetProperty("Id").GetValue(obj, null)).FirstOrDefault());
    
                var _logger = Mock.Of<ILogger<StudyService>>();
                StudyService _service = new StudyService(_logger, _data.Object);
    
                StudiesResponse result = _service.GetAllStudies().Result;
                StudiesResponse expectedResult = MockedDAOs.GetMockedStudiesResponse();
    
                var comparation = comparator.Compare(result, expectedResult);
    
                Assert.True(comparation.AreEqual); 
            }
    

    As you can see I'm using KellermanSoftware.CompareNetObjects to do the assertion, that's why I had to modify the method to test, parsing the Participators from a LinQ WhereSelect response to a List, so the comparator would not see a difference with my constructed expected response.

    This is the slightly different method code:

            public async Task<StudiesResponse> GetAllStudies()
            {
                StudiesResponse studies = new StudiesResponse();
                List<StudyReponse> list = new List<StudyReponse>();
                foreach (StudyDAO study in await _dataRepository.GetEntitiesAsync<StudyDAO>())
                {
                    StudyReponse resp = new StudyReponse()
                    {
                        StudyCode = study.StudyCode,
                        Participators = _dataRepository.GetEntitiesAsync<RoleUserDAO>(new { @StudyId = study.Id }).Result.Select(x => new ParticipatorsResponse()
                        {
                            UserEmail = _dataRepository.GetEntityAsync<UserDAO>(new { @Id = x.Id }).Result.Email,
                            RoleName = _dataRepository.GetEntityAsync<RoleDAO>(new { @Id = x.Id }).Result.Name
                        }).ToList()
                    };
                    list.Add(resp);
                }
                studies.Studies = list;
                return studies;
            }