如何对数据库访问逻辑进行单元测试?

How to unit test database access logic?

我有一个基于 EF Code First 使用 MSSQL server 的项目。在我的一个存储库中,我正在使用 PredicateBuilder 动态构建查询。每次代码发生变化时手动测试所有可能的结果,非常耗时。

出于这个原因,我想通过单元测试使其自动化。我正在考虑使用 sql compact 进行单元测试,使用 MSSQL server 进行生产。但是如何为 sql compact 服务器启用迁移?

这是 dbContext class:

public partial class ApplicationDbContext :
        IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationDbContext() : base("name=DefaultConnection") { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());
        base.OnModelCreating(modelBuilder);
     }
}

存储库:

public class FilterRepository : IFilterRepository
{
    private ApplicationDbContext _dbContext;

    public FilterRepository(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
        DbInterception.Add(new CommandInterceptor());
    }

    public IEnumerable<Person> GetPersons(Filter filter)
    {
        try
        {
            var persons = PredicateBuilder.False<Person>();

            _dbContext.Configuration.AutoDetectChangesEnabled = false;

            var result = _dbContext.Persons
                            .AsNoTracking() 
                            .Where(persons)
                            .OrderBy(x => x.Name)
                            .Skip(filter.Skip)
                            .Take(10)
                            .ToList();

            _dbContext.Configuration.AutoDetectChangesEnabled = true;

            return result;
        }
        catch (Exception ex)
        {

        }
    }
}

好的,所以切换到不同的数据库进行测试是 (imo) 一个坏主意。

这里有一些术语供您参考,可能有助于您更好地组织测试。

单元测试用于测试您的业务功能,通常您会为此模拟您的数据,因为您想要测试您的域 classes 中的输入(数据)发生了什么,而不是在哪里他们来自.

集成测试用于测试您的业务领域层如何与您的服务层交互(您的数据层是服务层),我也将测试查询的正确性视为集成测试,目的是 运行他们。

因此,在您的情况下,不要混淆事物并可能添加因 2 个数据库工作方式不同而导致的意外行为。如果您正在测试您的业务功能,请为此模拟您的数据。它一开始速度更快,您将测试您想要测试的内容。

通过集成测试,您正在测试与服务层的交互是否正确,在这种情况下,您的测试并不是真正测试业务逻辑是否有效,这应该包含在单元测试中;测试您的查询 return 其谓词的正确数据,以及要保留的任何数据是否正确保留。此外,任何正在进行的交易都按照您的预期进行。场景的端到端测试也是有效的集成测试。

您绝对需要在与生产相同的数据库平台上执行此操作,不要期望 SQL Compact 和 SQL Server 的行为方式相同。

编辑...评论。

因此,您模拟存储库调用的正常方法是使用依赖注入,您不必这样做,但它更容易且几乎是最佳实践。

想法是,在您的域 class 中使用您的数据,您将首先获取您的存储库,或者从注入到构造函数或从中提取的 DI 容器中查询 class DI 容器

// in your domain class you would have something like...
    var repo = container.Get<IRepository>();
    var myList = repo.GetMyObjects(predcate);

因此,使用 Moq,您现在可以简单地模拟该调用

//Where you do your container registration..
var repo = Mock<IRepository>
repo.Setup( o => o.GetMyObject(predecate)).Returns( (predecate) => <your dummy list>));
container.Register(repo.Object);
// Then later on your business domain object gets the dummy repo instead.

注意这是伪代码,根据使用的 DI 和 Mocking 框架会略有不同。