How to Mock DbSet of EF code First ?

6 posts, 0 answers
  1. Md.Hasanuzzaman
    Md.Hasanuzzaman avatar
    31 posts
    Member since:
    Apr 2011

    Posted 30 Dec 2013 Link to this post

    Dear sir,
    I am a big fan of telerik control. Recently I have convinced my boss to use use JustMock for my current project. Everything was running smooth and our company was totally impressed with it until I stuck in a problem. I have tried my level best to solve it but can't find a suitable solution. My colleague, Google, Stackoverflow everything failed to satisfy me, so finding no way I came to you with the hope that you would rescue me from this unsolvable problem. I have included my code here, please have a look on it.

    Problem : Unable to Mock DbSet 

    we are test this Repository but don`t understand How to do it. 

     public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new()
        {
            protected readonly DbContext DbContext;
            protected DbSet<T> DbSet;

            public BaseRepository(DbContext dbContext)
            {
                DbContext = dbContext;
                DbSet = DbContext.Set<T>();
            }

            public void Add(T entity)
            {
                DbSet.Add(entity);
            }
    }

    we are tried following code but we are failed.
     
     public class BaseRepositoryTest
        {
            readonly TimeSketchContext _mockDataContext = Mock.Create<TimeSketchContext>();
            private readonly BaseRepository<EmployeeSkill> _repository;
            public BaseRepositoryTest()
            {
                Mock.Arrange(() => _mockDataContext.EmployeeSkill).ReturnsCollection(GetEmployeeSkills());
                _repository = new BaseRepository<EmployeeSkill>(_mockDataContext);
            }

            [Fact]
            public void Add()
            {
                var employeeSkill = GetEmployeeSkill();
                _repository.Add(employeeSkill);
                _mockDataContext.SaveChanges();
                var allSkill = _repository.All();
                Assert.Equal(2, allSkill.Count()); //we are get 0 item here and out test is failed.
            }

            [Fact]
            public void Get_All_Test()
            {
                var allSkill = _repository.All();
                Assert.Equal(1, allSkill.Count()); //we are get 0 item here and out test is failed.

            }


            #region Private Methods
            private EmployeeSkill GetEmployeeSkill()
            {
                return new EmployeeSkill
                {
                    SkillDescription = "aa",
                    SkillName = "bbbb",
                    Id = 1
                };
            }

            private IEnumerable<EmployeeSkill> GetEmployeeSkills()
            {
                return new List<EmployeeSkill>
                {
                    GetEmployeeSkill()
                };
            }

            #endregion
        }
    if any books on it please refer.
  2. Stefan
    Admin
    Stefan avatar
    198 posts

    Posted 31 Dec 2013 Link to this post

    Hello Mr. Hasanuzzaman,

    Reading through your test, it appears that mock the dependency of BaseRepository<T>, which is a DbContext, but do not arrange all of its methods that the system under test depends on. Whenever you create a mock, you should carefully choose its behavior. In your code you create a recursive loose mock (that's the default behavior of Mock.Create<T>()) - this means that all method calls to the mock will behave like stubs or will return stubs recursively by default. This means, for example, that DbSet = DbContext.Set<T>(); will set DbSet to a stub - it will not set it to _mockDataContext.EmployeeSkill, unless explicitly arranged to do so. This also means that DbSet.Add(entity) will also behave like a stub - in other words it will do nothing (unless explicitly arranged).

    When testing without mocks, usually you assert the side effects created by the dependencies of the system under test. This is the same pattern I see in your own tests. When testing with mocks, you should assert the mocks directly. For example, in your code, you test that the BaseRepository.Add method works, by asserting its side effects - namely, that the number of items in the collection, that Add works on, is now 2. However, the test doesn't work because the collection is a stub, not a real collection - calling its Add method simply does nothing. Instead, you should simply assert that the Add method was called at all - if it was called, then, obviously, the code under test behaves correctly. Thus, your test will look like this:
    [Fact]
    public void Add()
    {
        var employeeSkill = GetEmployeeSkill();
        _repository.Add(employeeSkill);
        Mock.Assert(() => _mockDataContext.Set<EmployeeSkill>().Add(employeeSkill), Occurs.Once());
    }
    In the above method I call the _repository.Add() method and then assert that the .Add method of the underlying DbContext table was called exactly once with the same argument as the one passed to _repository.Add(). This example illustrates the basic test pattern when working with mocks - you don't assert side effects, you assert the mocks directly.

    For your second test, you must arrange the respective Set<T> method, instead of the property wrapper. So, your arrange statement should look like this:
    Mock.Arrange(() => _mockDataContext.Set<EmployeeSkill>()).ReturnsCollection(GetEmployeeSkills());
    This is necessary, because .Set<T> is the method on the mock that BaseRepository uses. It does not use the .EmployeeSkill property directly, so there is no meaning in setting it.

    For an introduction to mocking with JustMock I recommend the excellent 30 Days of TDD series.

    I hope that my explanation has been helpful. If you require further assistance during your trial, don't hesitate to write to us again. We would be more than happy to assist you in any way we can.

    Regards,
    Stefan
    Telerik
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
  3. DevCraft R3 2016 release webinar banner
  4. Md.Hasanuzzaman
    Md.Hasanuzzaman avatar
    31 posts
    Member since:
    Apr 2011

    Posted 01 Jan 2014 Link to this post

    Thank`s  Stefan.
    Your are really awesome. Your answered is really helpful.

    Now I am in another problem. I am unable to Mock Asynchronous Methods.

    Here is my code which I try for :

     My Class :

     public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new()
        {
            protected readonly DbContext InnerDbContext;
            protected DbSet<T> InnerDbSet;

            public BaseRepository(DbContext innerDbContext)
            {
                InnerDbContext = innerDbContext;
                InnerDbSet = InnerDbContext.Set<T>();
            }

            public virtual void Add(T entity)
            {
                InnerDbSet.Add(entity);
            }

            public virtual async Task UpdateAsync(T entity)
            {
                var newEntry = InnerDbContext.Entry(entity);
                if (newEntry.State != EntityState.Detached)
                {
                    var oldEntity = await FindAsync(entity.Id);
                    if (oldEntity == null)
                        throw new EntityNotFound();
                    var attachEntity = InnerDbContext.Entry(oldEntity);
                    attachEntity.CurrentValues.SetValues(newEntry);
                }
                else
                {
                    newEntry.State = EntityState.Modified;
                }
            }

            public virtual async Task RemoveAsync(T entity)
            {
                entity.IsDelete = true;
                await UpdateAsync(entity);
            }

            public virtual IQueryable<T> All()
            {
                return InnerDbSet.Where(x => !x.IsDelete);
            }

            public virtual Task<T> FindAsync(long id)
            {
                return InnerDbSet.FirstOrDefaultAsync(x => x.Id == id && !x.IsDelete);
            }

            public virtual IQueryable<T> Search(Expression<Func<T, bool>> expression)
            {
                return InnerDbSet.Where(x => x.IsDelete)
                    .Where(expression);
            }
        }

    My Test :

           readonly TimeSketchContext _mockDataContext = Mock.Create<TimeSketchContext>();
            private readonly BaseRepository<EmployeeSkill> _repository;
            public BaseRepositoryTest()
            {
                _repository = new BaseRepository<EmployeeSkill>(_mockDataContext);
            }

            [Fact]
            public async void Find_Should_Call_Once()
            {
                await _repository.FindAsync(Arg.AnyInt);
                Mock.Assert(() => _mockDataContext.Set<EmployeeSkill>().FirstOrDefaultAsync(x => x.Id == Arg.AnyInt && !x.IsDelete), Occurs.Once());
                // Mock.Assert(() => _mockDataContext.Set<EmployeeSkill>().LastOrDefault(x => x.Id == Arg.AnyInt && !x.IsDelete), Occurs.Once());  test is pass !!!

            }
           above test is also  pass if  change this FirstOrDefaultAsync to LastOrDefault

            [Fact]
            public async void Update_Should_Call_Once()
            {
                var employeeSkill = GetEmployeeSkill();
                employeeSkill.SkillName = "Skill Update";
                await _repository.UpdateAsync(employeeSkill);
                Mock.Assert(() => _repository.FindAsync(Arg.AnyInt), Occurs.Once());
            }
       
           Same Problem.
           
           [Fact]
            public async void Remove_Should_Call_Update()
            {
                await _repository.RemoveAsync(Arg.IsAny<EmployeeSkill>());
                Mock.Assert(() => _repository.UpdateAsync(Arg.IsAny<EmployeeSkill>()), Occurs.Once());
            }

    Thank`s in Advance.
  5. Kaloyan
    Admin
    Kaloyan avatar
    872 posts

    Posted 06 Jan 2014 Link to this post

    Hello Md.Hasanuzzaman,

    I have replied in forum thread with ID: 773091. Please, let's continue the discussion there as the issue now differs from the original forum thread title.

    Thank you for the understanding.

    Regards,
    Kaloyan
    Telerik
    Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
  6. Mark
    Mark avatar
    2 posts
    Member since:
    Jan 2015

    Posted 04 Mar 2015 Link to this post

    Hi Kaloyan,

    I have seen in many places a response stating 'I have replied in forum thread ID :(some number)'.
    But I am unable to see how we can find a forum thread by its ID number.
    If there is a way could you let me know if not could you provide the title of the forum thread with ID 773091

    Kind Regards
    Mark
  7. Zdravko
    Admin
    Zdravko avatar
    657 posts

    Posted 05 Mar 2015 Link to this post

    Hi Mark,

    Usually, the ID works when it comes to ticket thread and I am sure my colleague has provided this reference by accident.
    Here is a link to the forum thread.

    Regards,
    Zdravko
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
Back to Top
DevCraft R3 2016 release webinar banner