• ASP.NET Core 集成测试中结合 WebApplicationFactory 使用 SQLite 内存数据库


    SQLite 内存数据库(in-memory database)的连接字符串是  Data Source=:memory: ,它的特点是数据库连接一关闭,数据库就会被删除。而使用  services.AddDbContext 通过连接字符串配置 EF Core 时,EF Core 会在每次查询或 SaveChanges 后立即关闭数据库连接。在这样的情况下,集成测试中就无法在向 SQLite 内存数据库写入数据库后进行查询测试。

    为了解决上述问题,我们就不能让 EF Core 自己自动维护数据库连接,而只能改为手动模式,手工创建并打开 SqliteConnection 给 EF Core 使用,在用完之后的适当时候关闭连接。

    除此之外,由于在每次打开数据库连接都会创建新的数据库,所以还要解决在什么写入数据之前完成数据库的初始化。

    结合 WebApplicationFactory ,我们用下面继承自 WebApplicationFactory 的实现代码解决了问题。

    public class BlogWebAppFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
    {
        private DbConnection _dbConnection;
    
        public BlogWebAppFactory()
        { }
    
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            base.ConfigureWebHost(builder);
    
            builder.ConfigureServices(services =>
            {
                _dbConnection = new SqliteConnection("Data Source=:memory:");
                _dbConnection.Open();
                services.AddDbContext<EfUnitOfWork>(options =>
                {
                    options.UseSqlite(_dbConnection);
                });
            });
        }
    
        protected override TestServer CreateServer(IWebHostBuilder builder)
        {
            var server = base.CreateServer(builder);
    
            using (var scope = server.Host.Services.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<EfUnitOfWork>();
                dbContext.Database.EnsureCreated();
            }
    
            return server;
        }
    
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            _dbConnection?.Dispose();
        }
    }

    集成测试中的示例代码如下

    public class PostsWebApiTests : IClassFixture<BlogWebAppFactory<Startup>>
    {
        private readonly BlogWebAppFactory<Startup> _factory;
        private readonly HttpClient _httpClient;
    
        public PostsWebApiTests(BlogWebAppFactory<Startup> factory)
        {
            _factory = factory;
            _httpClient = factory.CreateClient();
        }
    
        [Fact]
        public async Task GetPostsByBlogIdsTest()
        {
            var fakePosts = SeedData();
            var blogIds = fakePosts.Select(p => p.BlogID).Distinct();           
            var response = await _httpClient.PostAsJsonAsync($"/blogposts/blogIds", blogIds);
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        }
    
        private IList<BlogPost> SeedData()
        {
            using (var scope = _factory.Server.Host.Services.CreateScope())
            {
                var efUnitOfWork = scope.ServiceProvider.GetRequiredService<EfUnitOfWork>();
    
                var blogSites = Builder<BlogSite>.CreateListOfSize(3).All()
                .Do(b => b.BlogID = 0)
                .Build();
    
                var fakePosts = Builder<BlogPost>.CreateListOfSize(12).All()
                .Do(x => x.Id = 0)
                .TheFirst(4).With(x => x.BlogSite = blogSites[0])
                .TheNext(4).With(x => x.BlogSite = blogSites[1])
                .TheNext(4).With(x => x.BlogSite = blogSites[2])
                .Build();
    
                efUnitOfWork.AddRange(fakePosts);
                efUnitOfWork.SaveChanges();
    
                return fakePosts;
            }
        }
    }
  • 相关阅读:
    MySQL之Web乱码问题
    MySQL之表操作
    Python学习笔记调式之抛出异常
    Python学习笔记调试之取得反向跟踪的字符串
    MySQL之库操作
    C#基础 冒泡排序
    C#基础 数组、二维数组
    C#基础 类及常用函数【string 、Math 、DiteTime 、TimeSpan】
    C#基础 异常语句 、跳转语句、while循环、穷举法、迭代法
    C#基础 循环语句【for】
  • 原文地址:https://www.cnblogs.com/dudu/p/9765937.html
Copyright © 2020-2023  润新知