首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用具有紧急加载功能的内存数据库对EF核进行单元测试

使用具有紧急加载功能的内存数据库对EF核进行单元测试
EN

Stack Overflow用户
提问于 2019-08-12 22:56:13
回答 1查看 7.8K关注 0票数 5

我正在为我的Web编写单元测试,除非从方法中移除包含(急切地从方法中加载),否则无法通过测试。我正在使用内存中的数据库来提供dbcontext,并且不知道它为什么不返回数据。谢谢您的帮助或建设性的批评。

这就是我要测试的方法。

注意事项:如果我注释掉.include语句,它将通过测试。

代码语言:javascript
复制
    public async Task<LibraryAsset> GetAsset(int assetId)
    {
        var asset = await _context.LibraryAssets
            .Include(p => p.Photo)
            .Include(p => p.Category)
            .Include(a => a.AssetType)
            .Include(s => s.Status)
            .Include(s => s.Author)
            .FirstOrDefaultAsync(x => x.Id == assetId);

        return asset;
    }

这是使用DbContext DB的基本inMemory:

代码语言:javascript
复制
    public DataContext GetDbContext()
    {
        var builder = new DbContextOptionsBuilder<DataContext>();

        if (useSqlite)
        {
            // Use Sqlite DB.
            builder.UseSqlite("DataSource=:memory:", x => { });
        }
        else
        {
            // Use In-Memory DB.
            builder.UseInMemoryDatabase(Guid.NewGuid().ToString());
        }

        var DataContext = new DataContext(builder.Options);

        if (useSqlite)
        {
            // SQLite needs to open connection to the DB.
            // Not required for in-memory-database and MS SQL.
            DataContext.Database.OpenConnection();
        }

        DataContext.Database.EnsureCreated();

        return DataContext;
    }

这是一个考验:

代码语言:javascript
复制
    [Fact]
    public async void GetAssetById_ExistingAsset_ReturnAsset()
    {
        using (var context = GetDbContext())
        {
            ILogger<LibraryAssetService> logger = new 
            NullLogger<LibraryAssetService>();

            var service = new LibraryAssetService(context, _logger);

            var asset = new LibraryAsset
            {
                Id = 40,
                NumberOfCopies = 20,
                Title = "",
                Year = 1992,
                Status = new Status { Id = 1 },
                AssetType = new AssetType { Id = 1 },
                Author = new Author { Id = 1 },
                Category = new Category { Id = 2 },
                Photo = new AssetPhoto { Id = 1 }
            };

            context.LibraryAssets.Attach(asset);

            context.Add(asset);
            context.SaveChanges();

            var actual = await service.GetAsset(40);
            Assert.Equal(40, actual.Id);
        }
    }

这是我第一次写单元测试,我基本上是在学习。请随时指出你可能注意到的任何其他错误。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-13 04:41:08

您的代码有一些问题:

  1. 如果您的实际数据库是关系数据库,则避免使用UseInMemoryDatabase数据库进行测试,因为它不支持关系行为。
  2. 将“安排”上下文与“法案”上下文分离。这意味着,创建一个用于准备测试、添加测试数据等的新DataContext,并为SUT创建另一个LibraryAssetService(本例中为LibraryAssetService)。DbContext存储本地数据(内存中),这些数据可能不存在于数据库中,而且在某些情况下可能会显示假绿色测试!
  3. 添加资产时不需要Attach。这可能会在sqlite中创建Foreign key constraint错误。

为了简单起见,我删除了一些导航和参数。因此,假设LibraryAssetService是这样的:

代码语言:javascript
复制
public class LibraryAssetService
{
  public LibraryAssetService(DataContext context)
  {
     _context = context;
  }

  private readonly DataContext _context;

  public async Task<LibraryAsset> GetAsset(int assetId)
  {
     var asset = await _context.LibraryAssets
        .Include(p => p.Photo)
        .Include(s => s.Author)
        .FirstOrDefaultAsync(x => x.Id == assetId);

     return asset;
  }
}

考试班:

代码语言:javascript
复制
public class LibraryAssetServiceTests
{
  public LibraryAssetServiceTests()
  {
     _factory = new TestDataContextFactory();
  }

  private TestDataContextFactory _factory;

  [Fact]
  public async void GetAssetById_ExistingAsset_ReturnAsset()
  {
     // Arrange
     using (var context = _factory.Create())
     {
        var asset = new LibraryAsset
        {
           Id = 40,
           Author = new Author { Id = 1 },
           Photo = new Photo { Id = 1 }
        };

        context.Add(asset);
        context.SaveChanges();
     }

     // Act
     using (var context = _factory.Create())
     {
        var service = new LibraryAssetService(context);
        var actual = await service.GetAsset(40);

        // Assert
        Assert.Equal(40, actual.Id);
        Assert.Equal(1, actual.Author.Id);
        Assert.Equal(1, actual.Photo.Id);
     }

  }
}

最后,一个小助手类来为您的测试准备DataContext。在测试类之外提取这类东西是很好的做法。在使用sqlite内存数据库进行测试时要记住的重要是,在测试期间应该保持连接保持打开。不管您创建了多少DbContext实例。xUnit为每个测试方法创建测试类的实例。因此,将为每个测试创建一个TestDataContextFactory实例,您可以选择。

代码语言:javascript
复制
public class TestDataContextFactory
{
  public TestDataContextFactory()
  {
     var builder = new DbContextOptionsBuilder<DataContext>();
     var connection = new SqliteConnection("DataSource=:memory:");
     connection.Open();
     builder.UseSqlite(connection);

     using (var ctx = new DataContext(builder.Options))
     {
        ctx.Database.EnsureCreated();
     }

     _options = builder.Options;
  }

  private readonly DbContextOptions _options;

  public DataContext Create() => new DataContext(_options);
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57469212

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档