如何模拟由代码优先策略创建的实体框架数据库?

时间:2012-07-13 01:31:39

标签: c# entity-framework unit-testing mocking

我有一个数据库存储库类:

public class DatabaseRepository : IRepository
    {
        private readonly Database _database;

        public DatabaseRepository(Database database)
        {
            _database = database;
        }

        ...

        public void Delete<TObject>(TObject entity) where TObject : BaseEntity
        {
            var dbSet = DbSet<TObject>();
            dbSet.Remove(entity);
            Save();
        }

        ...

        private void Save()
        {
            try
            {
                 _database.SaveChanges();
            }
            catch(DbEntityValidationException dbEx)
            {
                // do some action
            }
        }    
    }

我需要测试catch方法的private void Save()块,所以我需要类似......

[TestMethod]
public void SaveShouldDoSomethingIfDabaBaseConnectFalls()
{
    Mock<Database> mockDb = new Mock<Database>();
    mockDb.Setup(db => db.SaveChange()).Throws(new DbEntityValidationException());

    IRepository repository = new DatabaseRepository(mockDb.Object);

    ...
}

所以我的问题是如何模拟实体框架数据库? Mock<Database> mockDb = new Mock<Database>(); - 如何正确写出????对于模拟,我使用Moq

1 个答案:

答案 0 :(得分:3)

  1. IDatabase定义DbContext界面,其中包含典型的IIDbSet<T>属性
  2. 实施FakeDbSet<T>: IDbSet<T>
  3. 更新Repository以使用IDatabase代替Database
  4. 之后,您可以构建模拟IDatabase

    http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/

    通过这样做,请记住针对虚假数据库集实施的单元测试并不能保证您的代码能够对抗真实数据库。

    LINQ-to-Entities(真实DbSet)不支持LINQ-to-Objects(FakeDbSet)所做的许多功能。因此,当您使用数据库时,您的代码可能会在执行时失败。

    此限制不会使针对伪造的DbSet实施的单元测试无效。测试仍然可以测试存储库中实现的业务规则。但是您需要针对真实数据库LINQ到实体数据库提供程序运行每个更新的linq语句(手动或从集成测试),以确保提供程序支持它。

    这里有关于这个“圣战”主题的更多信息 - Fake DbContext of Entity Framework 4.1 to Test