Unit testing 似乎无法帮助任何人?

Unit testing 似乎无法帮助任何人?,unit-testing,mocking,moq,repository-pattern,entity-framework-4.1,Unit Testing,Mocking,Moq,Repository Pattern,Entity Framework 4.1,我的任务是评估codeFirst,并可能用于我们未来的所有项目。 评估基于对现有数据库使用codeFirst 想知道是否有可能使用codeFirst 4.1模拟存储库(没有赝品) 其思想是将存储库注入到服务中,然后moq存储库 我一直在网上寻找,但我只找到了一个使用假货的例子。我不想使用假货,我想使用最低起订量 我认为我的问题在于DAL的体系结构。(我想使用unitOfWork等。我需要展示一个工作moq示例) 以下是我的尝试(失败惨重),因为我对代码优先4.1缺乏了解。 我还上传了一个解决方案

我的任务是评估codeFirst,并可能用于我们未来的所有项目。 评估基于对现有数据库使用codeFirst

想知道是否有可能使用codeFirst 4.1模拟存储库(没有赝品)

其思想是将存储库注入到服务中,然后moq存储库

我一直在网上寻找,但我只找到了一个使用假货的例子。我不想使用假货,我想使用最低起订量

我认为我的问题在于DAL的体系结构。(我想使用unitOfWork等。我需要展示一个工作moq示例)

以下是我的尝试(失败惨重),因为我对代码优先4.1缺乏了解。 我还上传了一个解决方案,以防有人心情好,想改变它

我愿意接受对我的Dal的建议和全面修改。理想情况下使用Unity等。。但我以后会担心的。 最重要的是,我需要能够嘲笑它。如果没有能力使用最低起订量,我们将使用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();
    }
}
//CodeFirst.Tests项目
[测试类]
公开课学生测验
{
[测试方法]
public void应该能够验证是否调用了
{
//todo重做测试一次,我可以让一个简单的工作
//安排
var repository=newmock();
var expectedStudents=新列表();
repository.Setup(x=>x.GetAll()).Returns(expectedStudents);
//表演
var studentService=newstudentservice(repository.Object);
GetAll();
//断言
Verify(x=>x.GetAll(),Times.atlestOnce());
}
}
//代码优先。公共项目
公立班学生
{
公共int StudentId{get;set;}
公共字符串名称{get;set;}
公共字符串姓氏{get;set;}
}
公共接口IStudentService
{
IEnumerable GetAll();
}
//代码优先。服务项目
公共班级学生服务:IStudentService
{
私人是学生安置处(studentRepository);;
公共学生服务
{
}
公共学生服务(IStudeDepository studentRepository)
{
_studentRepository=studentRepository;
}
公共IEnumerable GetAll()
{
//TODO当使用moq进行模拟时,这实际上会调用db,因为我们需要一个单独的类。
使用(var ctx=新学校上下文(“学校数据库”))
{
_studentRepository=新studentRepository(ctx);
var studentRepository.GetAll().ToList();
留学生;
} 
}
}
//CodeFirst.Dal项目
公共接口IRepository,其中T:class
{
T GetOne(表达式谓词);
IEnumerable GetAll();
IEnumerable Find(表达式谓词);
无效添加(T实体);
无效删除(T实体);
T单(Func谓词);
T第一(Func谓词);
}
公共类RepositoryBase:IRepository,其中T:class
{
专用只读IDbSet _dbSet;
公共存储库(DbContext DbContext)
{
_dbSet=dbContext.Set();
如果(_dbSet==null)抛出新的InvalidOperationException(“无法创建dbSet”);
}
受保护的虚拟集查询
{
获取{return\u dbSet;}
}
公共T GetOne(表达式谓词)
{
返回Query.Where(谓词).FirstOrDefault();
}
公共IEnumerable GetAll()
{
返回Query.ToArray();
}
公共IEnumerable查找(表达式谓词)
{
返回Query.Where(谓词).ToArray();
}
公共无效添加(T实体)
{
_添加(实体);
}
公共作废删除(T实体)
{
_删除(实体);
}
公共T单(Func谓词)
{
返回Query.Where(谓词).SingleOrDefault();
}
公共T优先(Func谓词)
{
返回Query.Where(谓词).FirstOrDefault();
}
}
公共课堂背景:DbContext
{
公共学校上下文(字符串connectionString):基本(connectionString)
{
Database.SetInitializer(null);
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
//不知道为什么我必须这样做。在使用集成测试时没有这个
//与单元测试相反,它不起作用。
modelBuilder.Entity().ToTable(“学生”);}
公共数据库集学生{get;set;}
}
公共界面是用户存储:IRepository
{
}
公共课堂学生报告:RepositoryBase,IstudeRepository
{
公共研究职位(DbContext DbContext)
:base(dbContext)
{
}
公共IEnumerable GetStudents()
{
返回GetAll();
}
}
再次请随意修改或任何需要的东西,以帮助我得到一些东西在一起


非常感谢您的帮助

我看到的问题是,您正在丢弃模拟对象并新建一个新实例

_studentRepository = new StudentRepository(ctx);
也许在接口上添加一个方法来添加上下文对象并重用注入构造函数中的同一实例

using (var ctx = new SchoolContext("SchoolDB"))
    {
        _studentRepository.Context = ctx;
        var students = _studentRepository.GetAll().ToList();
        return students;
    } 
}

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

非常令人惊讶的是,您在评估EFv4.1时高度重视模拟和单元测试,同时定义了根本不可单元测试(使用模拟)的服务方法。服务方法的主要问题是没有将存储库/上下文作为依赖项传递,因此不能对其进行模拟。测试您的服务而不使用真实存储库的唯一方法是
public class StudentService : IStudentService
{
    private readonly IStudentRepository _studentRepository;

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

    public IEnumerable<Student> GetAll()
    {
         return _studentRepository.GetAll().ToList();
    }
}
[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);
    }
}