6

我偶然发现了下一个问题......我有数据库上下文:

// For support unit testing... 
public interface IDbContext : IDisposable
{
   IQueryable<Hardware> Hardwares { get; }
   IQueryable<ProviderHardware> ProviderHardwares { get; }
}

// Real DbContext (EF 4.0, Code First)
public class PrimaryDbContext : DbContext, IDbContext
{
   public DbSet<Hardware> Hardwares { get; set; }
   public DbSet<ProviderHardware> ProviderHardwares { get; set; }

   IQueryable<Hardware> IDbContext.Hardwares
     { get { return Hardwares; } }
   IQueryable<ProviderHardware> IDbContext.ProviderHardwares
     { get { return ProviderHardwares; } } 
   ...
}

我尝试获取 ProviderHardwares 表中不存在的所有硬件:

var hardwaresRemoved = db.Hardwares.Where(i => (i.IsAvailable == true) &&
   (db.ProviderHardwares.Count(j => j.Article == i.Article) == 0)).ToList();

如果我严格使用 PrimaryDbContext,例如“PrimaryDbContext db = new PrimaryDbContext();” 一切正常。但是如果我隐式使用它“IDbContext db = new PrimaryDbContext();” 我得到一个例外:

无法创建“ConfiguratorMvcApplication.DomainModels.ProviderHardware”类型的常量值。此上下文仅支持原始类型(“例如 Int32、String 和 Guid”)。

总结一下,我无法替换 IQueryable 上的 DbSet。在这种情况下我如何使用单元测试?我希望有人已经解决了这个问题......非常感谢!

4

2 回答 2

4

我最终为每个 DbSet 提供了两个属性:一个是 IQueryable 类型,一个是 DbSet 类型。IQueryable 属性在接口中定义,它将调用中继到具体实现(DbSet 类型的属性),如下所示:

// Exists in the interface
public IQueryable<AccountContact> AccountContacts
{ 
    get
    {
        return DbAccountContacts;
    }
    set
    {
        DbAccountContacts = (DbSet<AccountContact>)value; 
    }
}

// Exists only in the implementation
public DbSet<AccountContact> DbAccountContacts { get; set; }

有了这个设置,我就可以让 mocking 正常工作,并且可以对代码进行单元测试。

这对于 OP 来说绝对为时已晚,但也许这可以帮助像我一样在同一个问题上苦苦挣扎的人。

于 2016-06-14T20:04:27.710 回答
-2

我建议您最好保留 DbSets 并进行包括数据库在内的集成测试。

因为,尽管通过模拟数据库的单元测试可能会有些用处,但使用真实数据库进行测试会更好(但这不是单元测试)。

在 ClassInitialize 上擦除数据库和/或创建用于测试的初始数据。

如果您使用连接字符串创建 App.config 文件,您可以拥有一个单独的测试数据库,如果您使用的是 EF Code First,您可以免费获得它。

最好的祝福。

于 2011-09-01T06:31:25.483 回答