单元测试与集成测试:Entity Framework Core In memory

Unit Tests vs Integration tests: Entity Framework Core In memory

我目前正在使用 EF Core 2.0 开发 ASP.NET Core 2.0 Web API。我计划实施 Repository + UnitOfWork 模式,并且我已经创建了抽象、接口等。由于我遵循 TDD 方法,我想在继续实施之前在这些接口上编写测试。

我面临的问题主要与语义有关。我在我的解决方案中创建了两个项目,一个用于单元测试,一个用于集成测试。对我来说很明显,同时测试数据库的测试不是单元测试,因此应该放在 IntegrationTests 项目中。问题是,我计划使用 EntityFrameworkCore.InMemory 提供程序并为每个测试启动一个假的内存数据库。

所以每个测试都应该有这样的结构:

[TestClass]
public class GamesRepositoryTest
{
    AppDbContext _context;
    IGamesRepository _repository;

    public GamesRepositoryTest()
    {

    }

    [TestInitialize]
    public void Initialize()
    {
        DbContextOptionsBuilder<AppDbContext> builder = new DbContextOptionsBuilder<AppDbContext>().UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString());
        _context = new AppDbContext(builder.Options);
        _repository = new GamesRepository(_context);
    }

    [TestCleanup]
    public void Cleanup()
    {
        _context.Database.EnsureDeleted();
    }
}

所以我的问题是,EntityFrameworkCore.InMemory 是否提供了足够的抽象级别,以便上面的 class 可以被视为单元测试,还是我应该将它放在 IntegrationTests 项目中?

新的in-memory provider把大家的脑洞都搞糊涂了。首先,让我们弄清楚它的目的:它是一个测试数据提供者。而已。您可以轻松模拟出 DbContext 和 return 静态列表或其他内容。内存中提供程序只是为您提供了一种更简单的方法来设置该测试脚手架。它不适合集成测试,因为您实际上不会在生产中使用它。适当的集成测试会击中您的生产设置的真实副本。

也就是说,Entity Framework Core 的新内存提供程序的主要问题是现在人们似乎在滥用它来测试他们不应该测试的东西。 EF Core 已经过良好测试,因此您应该只测试 您的 应用程序代码。同样,只需将其视为模拟,而无需实际设置模拟。只要你这样做,你应该没问题。

基于所有这些,为了回答您的问题,您的测试应该是单元测试,如果除了您实际创建集成测试之外没有其他原因,您不应该使用内存提供程序。只需确保您确实在进行单元测试。

如果您使用真实的 dbContext 进行测试,无论它是访问 RDBMS 还是 InMemory 提供程序,这都是一个集成测试。为什么?因为您正在测试该框架的实现,而不是您方法中的代码 运行。单元测试仅测试 "unit" 代码 运行,通常是单个方法(而不是其协作者)。

EF Core 的 InMemory 提供程序与使用真实数据库进行的测试并非 100% 相同。事实上,有相当多的差异。它在开发时最有用的 IME 显示系统如何使用一些种子数据以及功能测试可以验证整个系统是否按预期工作(例如,使用 TestServer)。

如果您的单元测试项目只包含单元测试,那么它不应该依赖于特定于基础结构的代码,例如 EF Core。它通常应该只依赖于您自己正在测试的项目,以及您用于测试的任何工具(例如 xUnit、Moq 等)。如果您发现自己引入了基础架构依赖项,那么很可能您正在编写集成测试。