You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MsTest中SQLite内存数据库无法清空的解决办法

问题描述

我有一个MsTest项目,代码如下:

private MyDbContext _dbCtx;

private MyDbContext CreateSqlLiteDbCtx()
{
    var dbConnection = new SqliteConnection()
    {
        ConnectionString = "Data Source=:memory:",
    };

    dbConnection.Open();
    var _contextOptions = new DbContextOptionsBuilder<MyDbContext>()
                       .UseSqlite(dbConnection)
                       .Options;

    return new MyDbContext(_contextOptions);
}

[TestInitialize]
public void InitTests()
{
    _dbCtx= CreateSqlLiteDbCtx();
}

[TestCleanup]
public void CleanUp()
{
    _dbCtx?.Database.EnsureDeleted(); // Remove from memory
    _dbCtx?.Dispose();
}

[TestMethod] 
public async Task MyTest() 
{   
  if (_dbCtx.Database.EnsureCreated())   
   {
       // run test            
   }   
   catch (Exception)   
   {
     throw;  
   } 
 }

内存数据库中已存在无效数据,我希望清空数据库以获得全新的测试环境,但使用EnsureDeleted重新运行单元测试后并未生效,请问该如何彻底清空这个数据库?

解决方案

1. 先搞懂内存SQLite的核心特性

内存SQLite数据库的生命周期完全绑定在打开的连接上,只要连接没关闭,数据库就会一直存在于内存中。你当前的清理逻辑只Dispose了上下文,但底层的SQLite连接可能没被正确关闭释放,导致旧数据库残留。

2. 修正清理逻辑,彻底销毁连接

修改CleanUp方法,手动关闭并释放底层的SQLite连接:

[TestCleanup]
public void CleanUp()
{
    if (_dbCtx != null)
    {
        // 获取上下文绑定的SQLite连接
        var dbConnection = _dbCtx.Database.GetDbConnection();
        // 确保连接关闭
        if (dbConnection.State == System.Data.ConnectionState.Open)
        {
            dbConnection.Close();
        }
        // 释放上下文并置空
        _dbCtx.Dispose();
        _dbCtx = null;
    }
}

这样每次测试结束后,连接被关闭,内存数据库会被自动销毁,下一次测试初始化时会创建全新的空库。

3. 不要依赖EnsureCreated的返回值控制测试逻辑

内存数据库每次通过新连接创建时都是完全空的,EnsureCreated一定会返回true。如果之前的连接没释放,旧数据库没销毁,EnsureCreated会返回false,导致你的测试逻辑跳过执行,这也是数据残留的原因之一。建议直接执行测试逻辑,不需要判断EnsureCreated的结果:

[TestMethod] 
public async Task MyTest() 
{   
    // 直接执行测试逻辑,无需判断EnsureCreated
    // run test            
}

4. 备选方案:不清空数据库,直接重置数据

如果不想销毁连接,也可以在测试后手动清空所有表的数据并重置自增序列:

private async Task ResetDatabase()
{
    // 先禁用外键约束,避免清空表时出错
    await _dbCtx.Database.ExecuteSqlRawAsync("PRAGMA foreign_keys = OFF;");
    
    // 获取所有实体对应的表名
    var tableNames = _dbCtx.Model.GetEntityTypes()
        .Select(t => t.GetTableName())
        .Where(name => !string.IsNullOrEmpty(name))
        .Distinct();

    foreach (var table in tableNames)
    {
        // 清空表数据
        await _dbCtx.Database.ExecuteSqlRawAsync($"DELETE FROM {table};");
        // 重置自增序列(如果有的话)
        await _dbCtx.Database.ExecuteSqlRawAsync($"DELETE FROM sqlite_sequence WHERE name='{table}';");
    }
    
    // 恢复外键约束
    await _dbCtx.Database.ExecuteSqlRawAsync("PRAGMA foreign_keys = ON;");
    await _dbCtx.SaveChangesAsync();
}

在CleanUp中调用await ResetDatabase();即可实现数据重置。

内容的提问来源于stack exchange,提问作者SlappingTheBass12

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 12:25:30