无法将用于生产的 AppDbContext 设置替换为用于集成测试的内存数据库

问题描述 投票:0回答:1

我在我的 github 存储库中制作了一个最小化代码来说明问题:https://github.com/suugbut/MiniTest/tree/main

我正在学习集成测试来测试我的最小 API。我无法用用于集成测试的内存数据库替换生产的

AppDbContext
设置。我收到以下错误:

 Api.Test.TodoEndpoint_IntegrationTest.NumberOfTodos_MustBe_Two
   Source: TodoEndpoint_IntegrationTest.cs line 44
   Duration: 1.1 sec

  Message: 
Microsoft.Data.Sqlite.SqliteException : SQLite Error 1: 'no such table: Todos'.

  Stack Trace: 
SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
SqliteCommand.PrepareAndEnumerateStatements()+MoveNext()
SqliteCommand.GetStatements()+MoveNext()
SqliteDataReader.NextResult()
SqliteCommand.ExecuteReader(CommandBehavior behavior)
SqliteCommand.ExecuteDbDataReader(CommandBehavior behavior)
RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
Enumerator.InitializeReader(Enumerator enumerator)
<>c.<MoveNext>b__21_0(DbContext _, Enumerator enumerator)
NonRetryingExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
Enumerator.MoveNext()
Enumerable.TryGetSingle[TSource](IEnumerable`1 source, Boolean& found)
lambda_method157(Closure, QueryContext)
QueryCompiler.Execute[TResult](Expression query)
EntityQueryProvider.Execute[TResult](Expression expression)
TodoEndpoint_IntegrationTest.NumberOfTodos_MustBe_Two() line 50
RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

AppDbContext
用于生产

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(options =>
{
    var constr = builder.Configuration.GetConnectionString("DefaultConnection");
    options.UseSqlite(constr);
});

builder.Services.AddScoped<TodoRepo>();

var app = builder.Build();
// Others are removed for the sake of simplicity. 
"ConnectionStrings": {
  "DefaultConnection": "DataSource=Api.db"
}

如果您想检查

Program.cs
,请导航至 https://github.com/suugbut/MiniTest/blob/main/Api/Program.cs

AppDbContext
用于集成测试

public sealed class CustomWebApplicationFactory : WebApplicationFactory<Program>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        base.ConfigureWebHost(builder);
        builder.ConfigureServices(isc =>
        {
            var descriptor = isc.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));

            if (descriptor != null)
            {
                isc.Remove(descriptor);
            }

            isc.AddDbContext<AppDbContext>(options =>
            {
                var connection = new SqliteConnection("DataSource=:memory:");
                connection.Open();
                options.UseSqlite(connection);
            });

        });
    }

    // Others are removed for the sake of simplicity.
}

如果您想检查

CustomWebApplicationFactory.cs
,请导航至 https://github.com/suugbut/MiniTest/blob/main/Api.Test/CustomWebApplicationFactory.cs

集成测试

// Dependencies are removed for the sake of simplicity.

[Theory]
[InlineData(1)]
[InlineData(2)]
public async Task GetTodoById_Returns_OK(int id)
{
    // act
    var response = await _client.GetAsync($"/todos/{id}");

    // assert
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

    var content = await response.Content.ReadAsStringAsync();

    Assert.NotNull(content);
}

[Theory]
[InlineData(3)]
public async Task GetTodoById_Returns_NotFound(int id)
{
    // act
    var response = await _client.GetAsync($"/todos/{id}");

    // assert
    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}

[Fact]
public void NumberOfTodos_MustBe_Two()
{
    using (var scope = _factory.Services.CreateScope())
    {
        if (scope.ServiceProvider.GetRequiredService<AppDbContext>() is AppDbContext context)
        {
            var count = context.Todos.Count();
            Assert.Equal(2, count);
        }
    }
}

您还可以在 https://github.com/suugbut/MiniTest/blob/main/Api.Test/TodoEndpoint_IntegrationTest.cs

检查此测试
asp.net-core asp.net-web-api entity-framework-core minimal-apis asp.net-core-minimal-hosting-model
1个回答
0
投票

以下:

isc.AddDbContext<AppDbContext>(options =>
{
    var connection = new SqliteConnection("DataSource=:memory:");
    connection.Open();
    options.UseSqlite(connection);
});

将导致多次创建新连接,并且默认情况下 SQLite 内存中不共享。有多种选项可以解决此问题,例如只需将连接创建移到 lambda 之外:

var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
isc.AddDbContext<AppDbContext>(options =>
{
                
    options.UseSqlite(connection);
});
© www.soinside.com 2019 - 2024. All rights reserved.