2

I have been given the task to evaluate codeFirst and possible to use for all our future projects. The evaluation is based on using codeFirst with an existing database.

Wondering if it's possible to mock the repository using codeFirst 4.1.(no fakes)

The idea is to inject a repository into a service and moq the repository.

I have been looking on the net but I have only found an example using fakes.I dont want to use fakes I want to use moq.

I think my problem is in the architecture of the DAL.(I would like to use unitOfWork etc.. by I need to show a working moq example)

Below is my attempt(Failed miserably) due to lack of knowledge on Code first 4.1. I have also uploaded a solution just in case somebody is in good mood and would like to change it.

http://cid-9db5ae91a2948485.office.live.com/browse.aspx/Public%20Folder?uc=1

I am open to suggestions and total modification to my Dal.Ideally using Unity etc.. but I will worry about later. Most importantly I need to be able to mock it. Without ability to use MOQ we will bin the project using EF 4.1

Failed attempt

//CodeFirst.Tests Project
[TestClass]
public class StudentTests
{
    [TestMethod]
    public void Should_be_able_to_verify_that_get_all_has_been_called()
    {
        //todo redo test once i can make a simple one work
        //Arrange
        var repository = new Mock<IStudentRepository>();
        var expectedStudents = new List<Student>();
        repository.Setup(x => x.GetAll()).Returns(expectedStudents);

        //act
        var studentService = new StudentService(repository.Object);
        studentService.GetAll();

        //assert
        repository.Verify(x => x.GetAll(), Times.AtLeastOnce());
    }

}

//CodeFirst.Common Project
public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
}
public interface IStudentService
{
    IEnumerable<Student> GetAll();
}

//CodeFirst.Service Project
public class StudentService:IStudentService
{
    private IStudentRepository _studentRepository;

    public StudentService()
    {
    }

    public StudentService(IStudentRepository studentRepository)
    {
        _studentRepository = studentRepository;
    }


    public IEnumerable<Student> GetAll()
    {
        //TODO when mocking using moq this will actually call the db as we need a separate class.
        using (var ctx = new SchoolContext("SchoolDB"))
        {
            _studentRepository = new StudentRepository(ctx);
            var students = _studentRepository.GetAll().ToList();
            return students;
        } 
    }
}

//CodeFirst.Dal Project
public interface IRepository<T> where T : class
{
    T GetOne(Expression<Func<T, bool>> predicate);
    IEnumerable<T> GetAll();
    IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
    void Add(T entity);
    void Delete(T entity);
    T Single(Func<T, bool> predicate);
    T First(Func<T, bool> predicate);
}
public class RepositoryBase<T> : IRepository<T> where T : class
{
    private readonly IDbSet<T> _dbSet;

    public RepositoryBase(DbContext dbContext)
    {
        _dbSet = dbContext.Set<T>();
        if (_dbSet == null) throw new InvalidOperationException("Cannot create dbSet ");
    }

    protected virtual IDbSet<T> Query
    {
        get { return _dbSet; }
    }

    public T GetOne(Expression<Func<T, bool>> predicate)
    {
        return Query.Where(predicate).FirstOrDefault();
    }

    public IEnumerable<T> GetAll()
    {
        return Query.ToArray();
    }

    public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
    {
        return Query.Where(predicate).ToArray();
    }

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

    public void Delete(T entity)
    {
        _dbSet.Remove(entity);
    }


    public T Single(Func<T, bool> predicate)
    {
        return Query.Where(predicate).SingleOrDefault();
    }

    public T First(Func<T, bool> predicate)
    {
        return Query.Where(predicate).FirstOrDefault();
    }

}
 public class SchoolContext:DbContext
{
    public SchoolContext(string connectionString):base(connectionString)
    {
        Database.SetInitializer<SchoolContext>(null);
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Not sure why I have to do this.Without this when using integration testing
        //as opposed to UnitTests it does not work.
        modelBuilder.Entity<Student>().ToTable("Student");       }


    public DbSet<Student> Students { get; set; }
}
public interface IStudentRepository:IRepository<Student>
{

}
public class StudentRepository : RepositoryBase<Student>, IStudentRepository
{
    public StudentRepository(DbContext dbContext)
        : base(dbContext)
    {
    }

    public IEnumerable<Student> GetStudents()
    {
        return GetAll();
    }
}

Again feel free to modify or whatever is needed to help me to get something together.

Thanks a lot for your help

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
user712923
  • 1,515
  • 2
  • 16
  • 19

2 Answers2

3

When I started with repository and unit of work patterns I used the implementation similar to this (it is for ObjectContext API but converting it to DbContext API is simple). We used that implementation with MOQ and Unity without any problems. By the time implementations of repository and unit of work have evolve as well as the approach of injecting. Later on we found that whole this approach has serious pitfalls but that was alredy discussed in other questions I referenced here (I highly recommend you to go through these links).

It is very surprising that you are evaluating the EFv4.1 with high emphasis on mocking and unit testing and in the same time you defined service method which is not unit-testable (with mocking) at all. The main problem of you service method is that you are not passing repository/context as dependency and because of that you can't mock it. The only way to test your service and don't use the real repository is using some very advanced approach = replacing mocking and MOQ with detouring (for example Moles framework).

First what you must do is replacing your service code with:

public class StudentService : IStudentService
{
    private readonly IStudentRepository _studentRepository;

    public StudentService(IStudentRepository studentRepository)
    {
        _studentRepository = studentRepository;
    }

    public IEnumerable<Student> GetAll()
    {
         return _studentRepository.GetAll().ToList();
    }
}

Btw. this is absolutely useless code and example of silly layering which doesn't offer any useful functionality. Just wrapping the call to repository only shows that service is not needed at all as well as unit testing this method is not needed. The main point here is integration test for GetAll method.

Anyway if you want to unit thest such method with MOQ you will do:

[TestClass]
public class StudentsServiveTest
{
    private Mock<IRespository<Student>> _repo;

    [TestInitialize]
    public void Init()
    {
        _repo = new Mock<IRepository<Student>>();
        _repo.Setup(r => r.GetAll()).Returns(() => new Student[] 
            { 
                new Student { StudentId = 1, Name = "A", Surname = "B" },
                new Student { StudentId = 2, Name = "B", Surname = "C" }
            });
    }

    [TestMethod]
    public void ShouldReturnAllStudents()
    {
        var service = new StudentsService(_repo.Object);
        var data = service.GetAll();
        _repo.Verify(r => r.GetAll(), Times.Once());

        Assert.IsNotNull(data);
        Assert.AreEqual(2, data.Count);
    }
}
Community
  • 1
  • 1
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • thank you for your time just digesting the links.The service layer is needed as there will be many business validation code etc.that I have not bothered to put ,it's not just a proxy to the DAL. in the real world the service will be used by third parties which will go straight to th service.I just didnt want to pollute the code in my question with stuff that would not make it clear for you guys to help me.The main aim is mock the DAL so that I can validate the behaviour and not hit the db.In your test I can mock the service.(I am injecting an Irepository) but i cannot mock the dal. – user712923 Apr 24 '11 at 16:20
  • Reading some of your answers and experience I noticed that you would not use the Repository pattern if you were to start again.Ok I need to test my service without hitting the db.Moles seems quite a learning curve.MOQ seems the best choice to me.Does the UnitOfwork bring any benefit or just complexity.Isnt the idea of unit of work to abstract EF?From various post in the forum,it does not seem to be a concrete answer to all this,just very vague.How would you build your service and dal if you had to test your service and not hit the db – user712923 Apr 24 '11 at 17:18
  • Unit testing DAL is nonsense. DAL with ORM must be covered with integration tests touching real DB to proof that mapping and all ORM related stuff works. – Ladislav Mrnka Apr 24 '11 at 18:23
  • thinking about it.You are right about the DAL.You do need integration testing to prove that all the mapping is correct.What it the best practice you have found.Database snapshots on assemblyInitialize or may be mdf db inside your test project. – user712923 Apr 25 '11 at 05:06
0

The issue from what I can see is that you are throwing away the mock object and newing up a new instance

_studentRepository = new StudentRepository(ctx);

Perhaps add a method on the interface to add the context object and reuse the same instance that was injected in the constructor.

using (var ctx = new SchoolContext("SchoolDB"))
    {
        _studentRepository.Context = ctx;
        var students = _studentRepository.GetAll().ToList();
        return students;
    } 
}
aqwert
  • 10,559
  • 2
  • 41
  • 61
  • Thanks for your reply. I know I am doing something wrong.So my IDbset will not longer be readonly then.Cannot beleive how hard they made it to mock – user712923 Apr 24 '11 at 09:00
  • You are not actually mocking the Repository instance. You are just mocking the interface so IDbSet does not factor into it. I would imgine you can have separate unit tests for the StudentRepository class itself. – aqwert Apr 24 '11 at 09:33
  • the idea is to inject the IStudentRepository into the service and never hit the database.That is what I am trying to achieve.I was not planning to unit test the studentrepository as that would turn into an integration test no? ,may be i should.Would you spare 5 mins to put together some codesnippet to illustrate what you mean? I would be grateful or do you know a link where this has been done? – user712923 Apr 24 '11 at 15:56