如何使用lambda表达式Entity Framework / Repository模式进行单元测试

时间:2013-10-18 20:49:15

标签: c# entity-framework unit-testing dependency-injection lambda

我们正试图找出基本案例的单元测试点,如下面的代码所示。为这个有益的单元测试吗?我们不是试图测试实体框架。我们只是想确保lambda表达式做它应该做的...我们的想法是我们将使用DI传递IQIeryable的SOMETHING。在实践中它将是EF但是用于单元测试并且将是POCO对象/集合。这有道理吗?我们刚刚开始并希望在超出此基本代码之前掌握这些概念。

   public class CongressRepository
{
    CongressDb_DevEntities context = new CongressDb_DevEntities();

    CongressRepository(DbContext db)
    {
        context = (CongressDb_DevEntities) db;
    }

    public IQueryable<tMember> GetAllMembers
    {
        get { return context.tMembers; }
    }

    public IQueryable<tMember> GetVotingMembers
    {
        get { return context.tMembers.Where(x => x.age > 18); }
    }
}

3 个答案:

答案 0 :(得分:5)

EF使用LINQ to Entities,但在模拟EF时,您将切换到LINQ to Objects。由于LINQ to Entities和LINQ to Objects之间存在差异,因此可能会导致单元测试出现误报。如果没有集成测试,您只能在生产环境中看到这些差异/错误。

答案 1 :(得分:2)

单元测试代码的原因之一是确保准确性......

在你的例子中,有人无法在18岁生日或其与19岁生日之间的任何日子投票。我猜它应该是真的:

public IQueryable<tMember> GetVotingMembers
{
    get { return context.tMembers.Where(x => x.age >= 18); }
}

包含一系列合理成功和失败值的单元测试有助于确保您的代码符合您的意图: - )


  

但我们试图找到一个问题的原因是单位如何测试   工作

这可能是一个真正的痛苦! EF6刚刚宣布并且更容易模拟DbContext,但现在它需要很多设置......

重要的是Linq-to-Etities和Linq-to-Objects之间存在差异,因此您需要进行单元测试和集成测试。

有很多博客和SO questions相关但是......使用FakeDbSet作为一些google-fu的起点。

答案 2 :(得分:1)

对于使用DbContext的对象进行单元测试,您必须将其作为接口注入到存储库对象中。请按照以下步骤操作:

1.创建一个包含所有DbContext属性的接口,并从中派生出DbContext:

 public interface ICongressDbContext {
    IDbSet<Member> Members { get; set; }
    // repeat for all dbsets
 }

2.在构造函数中将此接口提供给您的存储库。这是你的依赖注入:

 private ICongressDbContext context;
 public CongressRepository(ICongressDbContext context){
     this.context = context;
 }

您需要使用依赖注入框架(如Autofac)传递上下文实例,或者您可以创建实例化对象的实例。

3.创建IDbSet的通用实现:https://gist.github.com/LukeWinikates/1309447。我们称之为FakeDbContext。

4.现在你有一个可模拟的接口和一个通用的DbSet实现,你可以创建你的模拟DbContext和你的模拟IDbSet。使用Moq,这看起来像:

        var dataContext = new Mock<ICongressDbContext>();
        var members = new List<Member> { // create your test data here };
        // set up the mocked context to use your fake db set with test data
        dataContext.SetupProperty(c => c.Members, new FakeDbContext<Member>(members));

        var repository = new CongressRepository(dataContext.Object);

        // start writing your test methods here

这将测试使用DbContext的对象,而不是DbContext本身 除了单元测试之外,您还需要编写使用真实DbContext的集成测试。 IQueryable支持许多方法,访问数据库时不支持这些方法。您还需要确保将数据模型正确映射到数据库。

我希望这有助于您开始使用。