Começando rápido

April 17, 2026 · View on GitHub

Instalação

Opção 1: referência de projeto (recomendado para desenvolvimento local)

<ItemGroup>
  <ProjectReference Include="../src/DbSqlLikeMem/DbSqlLikeMem.csproj" />
  <ProjectReference Include="../src/DbSqlLikeMem.SqlServer/DbSqlLikeMem.SqlServer.csproj" />
</ItemGroup>

Opção 2: referência a DLLs compiladas

dotnet build src/DbSqlLikeMem.slnx

Depois referencie no projeto de testes:

  • DbSqlLikeMem.dll
  • uma DLL de provider (ex.: DbSqlLikeMem.SqlServer.dll)

Opção 3: pacote NuGet (recomendado para consumo em times)

Instale apenas o provider que representa o banco que você quer simular. O pacote core (DbSqlLikeMem) entra como dependência transitiva.

Exemplos:

dotnet add package DbSqlLikeMem.SqlServer
dotnet add package DbSqlLikeMem.SqlAzure
dotnet add package DbSqlLikeMem.Npgsql
dotnet add package DbSqlLikeMem.MySql
dotnet add package DbSqlLikeMem.Oracle
dotnet add package DbSqlLikeMem.Sqlite
dotnet add package DbSqlLikeMem.Db2

NuGet e dependências

Cada provider é empacotado separadamente (ex.: DbSqlLikeMem.MySql, DbSqlLikeMem.Npgsql).

Durante o dotnet pack, cada provider inclui dependência de DbSqlLikeMem. Assim, ao instalar um provider via nuget.org, o núcleo é instalado automaticamente.

Dica: escolha um provider por projeto de teste (ou por suíte), conforme o dialeto que você precisa validar.

Compatibilidade de frameworks

Os pacotes de produção seguem os alvos centrais de src/code/Directory.Build.props: net462, netstandard2.0 e net8.0.

Os projetos de teste e test-tools usam o override dedicado: net462, net6.0 e net8.0.

Se houver impacto de distribuição ou versionamento, revise também docs/publishing.md.

Seleção de provider em runtime

Quando o banco é escolhido em tempo de execução, use uma factory:

using DbSqlLikeMem.MySql;
using DbSqlLikeMem.Npgsql;
using DbSqlLikeMem.Oracle;
using DbSqlLikeMem.SqlAzure;
using DbSqlLikeMem.Sqlite;
using DbSqlLikeMem.SqlServer;
using DbSqlLikeMem.Db2;

public static class DbSqlLikeMemFactory
{
    public static DbConnection Create(string provider)
    {
        return provider.ToLowerInvariant() switch
        {
            "mysql" => new MySqlConnectionMock(new MySqlDbMock()),
            "sqlserver" => new SqlServerConnectionMock(new SqlServerDbMock()),
            "sqlazure" or "azure-sql" or "azuresql" or "azure_sql" => new SqlAzureConnectionMock(new SqlAzureDbMock()),
            "oracle" => new OracleConnectionMock(new OracleDbMock()),
            "postgres" or "postgresql" or "npgsql" => new NpgsqlConnectionMock(new NpgsqlDbMock()),
            "sqlite" or "sqlite3" => new SqliteConnectionMock(new SqliteDbMock()),
            "db2" => new Db2ConnectionMock(new Db2DbMock()),
            _ => throw new ArgumentException($"Unsupported provider: {provider}")
        };
    }
}

Se carregar DLLs dinamicamente, garanta que o assembly do provider esteja disponível ao test runner.

Setup para testes (InternalsVisibleTo)

Se um assembly de testes customizado precisar acessar internal, adicione InternalsVisibleTo no core ou via AssemblyInfo.cs:

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("MyCustomTestAssembly")]

Exemplos de uso

Exemplo 1: schema fluente + execução compatível com Dapper (SQL Server)

using DbSqlLikeMem.SqlServer;

var db = new SqlServerDbMock { ThreadSafe = true };
using var connection = new SqlServerConnectionMock(db);

connection.DefineTable("user")
    .Column<int>("id", pk: true, identity: true)
    .Column<string>("name")
    .Column<string>("email", nullable: true)
    .Column<DateTime>("created", nullable: false);

connection.Open();

connection.Execute(
    "INSERT INTO user (name, email, created) VALUES (@name, @email, @created)",
    new { name = "Alice", email = "alice@mail.com", created = DateTime.UtcNow });

var users = connection.Query("SELECT * FROM user").ToList();

Exemplo 1b: criação de tabela via SQL + seed básico (SQL Server)

using DbSqlLikeMem.SqlServer;

var db = new SqlServerDbMock { ThreadSafe = true };
using var connection = new SqlServerConnectionMock(db);

connection.Open();
connection.Execute("CREATE TABLE users (Id INT PRIMARY KEY, Name VARCHAR(100) NOT NULL)");
connection.Execute("INSERT INTO users (Id, Name) VALUES (1, 'Alice')");

var users = connection.Query("SELECT * FROM users").ToList();

EN: This path is useful when you want to validate the DDL parser in addition to the fluent AddTable mapping. PT-BR: Esse caminho é útil quando você quer validar o parser de DDL além do mapeamento fluente via AddTable.

Exemplo 2: schema manual + seed (PostgreSQL)

using DbSqlLikeMem.Npgsql;

var db = new NpgsqlDbMock();
var table = db.AddTable("Users");

table.Columns["Id"] = new(0, DbType.Int32, false);
table.Columns["Name"] = new(1, DbType.String, false);

table.Add(new Dictionary<int, object?>
{
    { 0, 1 },
    { 1, "John Doe" }
});

using var connection = new NpgsqlConnectionMock(db);
var result = connection.Query("SELECT * FROM Users WHERE Id = @Id", new { Id = 1 });

Exemplo 3: inspeção de plano de execução e métricas

using DbSqlLikeMem.MySql;

using var cnn = new MySqlConnectionMock();
cnn.Define("users");
cnn.Column<int>("users", "Id");
cnn.Column<int>("users", "Active");
cnn.Seed("users", null, [1, 1], [2, 0], [3, 1]);

using var cmd = new MySqlCommandMock(cnn)
{
    CommandText = "SELECT Id FROM users WHERE Active = 1 ORDER BY Id"
};

using var reader = cmd.ExecuteReader();
while (reader.Read())
{
    // consume rows
}

Console.WriteLine(cnn.LastExecutionPlan);
// Campos úteis no plano:
// - EstimatedCost
// - InputTables
// - EstimatedRowsRead
// - ActualRows
// - SelectivityPct
// - RowsPerMs
// - ElapsedMs

Observações:

  • LastExecutionPlan traz o último plano gerado para a conexão.
  • LastExecutionPlans mantém o histórico da última execução do comando (útil para SQL com múltiplos SELECTs).
  • O plano também fica disponível no resultado (TableResultMock.ExecutionPlan) internamente no executor AST.

Exemplo 4: sequence por schema + override opcional de identity

using DbSqlLikeMem.SqlServer;

var db = new SqlServerDbMock();
db.CreateSchema("sales");

var orders = db.AddTable("orders", schemaName: "sales");
orders.AddColumn("id", DbType.Int64, false, identity: true);
orders.AddColumn("description", DbType.String, false);
orders.IdentityOf(nextIdentity: 100, allowInsertOverride: true);

using var connection = new SqlServerConnectionMock(db, "sales");
connection.Open();
connection.AddSequence("seq_orders", startValue: 1000, incrementBy: 5, schemaName: "sales");

connection.Execute("INSERT INTO sales.orders (id, description) VALUES (150, 'manual identity')");
connection.Execute("INSERT INTO sales.orders (id, description) VALUES (NEXT VALUE FOR sales.seq_orders, 'sequence value')");

var ids = connection.Query<long>("SELECT id FROM sales.orders ORDER BY id").ToList();

Observações do exemplo:

  • IdentityOf(..., allowInsertOverride: true) libera sobrescrita explícita da coluna identity só para esse cenário.
  • AddSequence(..., schemaName: "sales") registra a sequence no schema correto.
  • Para SQL Server e PostgreSQL, os fluxos validados hoje cobrem SELECT e INSERT com sequence simples e qualificada por schema; no PostgreSQL, o mock também cobre currval(...), setval(...) e lastval().

Exemplo 5: funções de sequence no PostgreSQL

using DbSqlLikeMem.Npgsql;

var db = new NpgsqlDbMock();
using var connection = new NpgsqlConnectionMock(db);
connection.Open();
connection.AddSequence("seq_orders", startValue: 10, incrementBy: 2);

var first = connection.ExecuteScalar<long>("SELECT nextval('seq_orders')");
var current = connection.ExecuteScalar<long>("SELECT currval('seq_orders')");
var updated = connection.ExecuteScalar<long>("SELECT setval('seq_orders', 30, false)");
var next = connection.ExecuteScalar<long>("SELECT nextval('seq_orders')");
var last = connection.ExecuteScalar<long>("SELECT lastval()");

Observações do exemplo:

  • currval(...) e lastval() são locais da sessão/conexão.
  • setval(..., false) faz o próximo nextval(...) retornar exatamente o valor informado.

Exemplo 6: sintaxe Oracle e DB2 para sequence

using DbSqlLikeMem.Oracle;
using DbSqlLikeMem.Db2;

var oracleDb = new OracleDbMock();
using var oracle = new OracleConnectionMock(oracleDb);
oracle.Open();
oracle.AddSequence("seq_orders", startValue: 100, incrementBy: 10);

var oracleNext = oracle.ExecuteScalar<long>("SELECT seq_orders.NEXTVAL");
var oracleCurr = oracle.ExecuteScalar<long>("SELECT seq_orders.CURRVAL");

var db2Db = new Db2DbMock();
using var db2 = new Db2ConnectionMock(db2Db);
db2.Open();
db2.AddSequence("seq_orders", startValue: 50, incrementBy: 5);

var db2Next = db2.ExecuteScalar<long>("VALUES NEXT VALUE FOR seq_orders");
var db2Previous = db2.ExecuteScalar<long>("VALUES PREVIOUS VALUE FOR seq_orders");

Observações do exemplo:

  • Oracle usa seq.NEXTVAL e seq.CURRVAL.
  • DB2 usa NEXT VALUE FOR seq e PREVIOUS VALUE FOR seq.
  • Os dois caminhos também aceitam nomes qualificados por schema no mock.

Checklist rápido de revisão de documentação

Use esta lista quando fizer alterações grandes no código:

  • Atualize a tabela de provedores/versões em README.md e docs/old/providers-and-features.md.
  • Verifique se exemplos de factory cobrem todos os providers suportados.
  • Confirme se novos recursos aparecem em pelo menos um guia de uso (docs/getting-started.md) e um guia de referência (docs/old/providers-and-features.md).
  • Se houver impacto de distribuição, revise docs/publishing.md.

Testes

dotnet test src/DbSqlLikeMem.slnx