似乎无法起订量 EF CodeFirst 4.1.帮助任何人? [英] Cannot seem to moq EF CodeFirst 4.1.Help anyone?

查看:26
本文介绍了似乎无法起订量 EF CodeFirst 4.1.帮助任何人?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的任务是评估 codeFirst 并可能用于我们未来的所有项目.评估基于将 codeFirst 与现有数据库一起使用.

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.

想知道是否可以使用 codeFirst 4.1 模拟存储库.(无假货)

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.

我认为我的问题出在 DAL 的架构上.(我想使用 unitOfWork 等.我需要展示一个有效的起订量示例)

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)

由于缺乏对 Code first 4.1 的了解,以下是我的尝试(惨败).我还上传了一个解决方案,以防万一有人心情好并想更改它.

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

我愿意接受建议和对我的 Dal 进行全面修改.理想情况下使用 Unity 等.但我稍后会担心.最重要的是我需要能够模拟它.如果无法使用 MOQ,我们将使用 EF 4.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

尝试失败

//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.

非常感谢您的帮助

推荐答案

当我开始使用存储库和工作单元模式时,我使用了类似于 this(它用于 ObjectContext API,但将其转换为 DbContext API 很简单).我们将该实现与 MOQ 和 Unity 一起使用,没有任何问题.随着时间的推移,存储库和工作单元的实现以及注入的方法已经发展.后来我们发现整个这种方法存在严重的缺陷,但这已经在我引用的其他问题中讨论过 这里(我强烈建议您浏览这些链接).

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).

令人惊讶的是,您正在评估 EFv4.1,高度重视模拟和单元测试,同时您定义了根本不可单元测试(使用模拟)的服务方法.您的服务方法的主要问题是您没有将存储库/上下文作为依赖项传递,因此您无法模拟它.测试您的服务并且不使用真实存储库的唯一方法是使用一些 非常先进的方法 = 用绕道代替模拟和最小起订量(例如 Moles 框架).

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();
    }
}

顺便说一句.这绝对是无用的代码和愚蠢的分层示例,它不提供任何有用的功能.仅包装对存储库的调用仅表明根本不需要服务,并且不需要对该方法进行单元测试.这里的重点是 GetAll 方法的集成测试.

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);
    }
}

这篇关于似乎无法起订量 EF CodeFirst 4.1.帮助任何人?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆