Integration Tests¶
Integration tests live under test/ and are grouped into five projects, all included in solutions/IntegrationTest.slnx.
Projects¶
| Project | Purpose |
|---|---|
TcfOss.DatabaseManager.Core.IntegrationTests |
Shared infrastructure reused by all other integration test projects |
TcfOss.DatabaseManager.MySql.IntegrationTests |
MySQL and MariaDB database fixtures and helpers |
TcfOss.DatabaseManager.MariaDb.IntegrationTests |
MariaDB-specific database fixtures |
TcfOss.DatabaseManager.MsSql.IntegrationTests |
SQL Server database fixtures and helpers |
TcfOss.DatabaseManager.App.IntegrationTests |
CLI end-to-end tests; depends on all of the above |
Core integration test infrastructure¶
TcfOss.DatabaseManager.Core.IntegrationTests contains primitives shared across all providers.
FakeDb¶
FakeDatabaseTestContainer/ contains FakeDbBuilder, FakeDbConfiguration, and FakeDbContainer.
FakeDbContainer implements IDatabaseContainer but performs no real network I/O—it is used for
tests that exercise CLI behavior that does not require a live database connection
(e.g. parse errors, file generation, no-connection error messages).
FsProjectFixture¶
FsProjectFixture creates an isolated temporary directory at construction time and exposes it
as RootDirectory. Tests copy schema files into it and run the CLI against it.
The fixture disposes the directory when the test is done.
Provider database fixtures¶
Each provider project owns version-pinned database fixtures. These are the objects that actually manage the lifecycle of a Docker container.
MySQL and MariaDB (TcfOss.DatabaseManager.MySql.IntegrationTests)¶
DatabaseFixtures/
DbFixture<TBuilder, TContainer, TContext> ← abstract; extends DbContainerFixture<,> (Testcontainers.Xunit)
FakeDbFixture ← wraps FakeDbContainer; no container started
MySqlFixture_[Version] ← sealed; one per pinned MySQL image tag
DbFixture<,,> extends DbContainerFixture<TBuilder, TContainer> from Testcontainers.Xunit,
which owns the container start/stop lifecycle and is itself an IAsyncLifetime. It adds:
- A GetDbContextOptions() method for constructing an EF Core DbContext against the container.
- A GetLibrarySchemaConfig() helper for building provider configuration.
- An InitializeLibrarySchema() helper that runs the library-schema initialisation script
inside the container.
Each MySqlFixture_[Version] is sealed, calls builder.WithStandardOptions("mysql:[tag]")
in Configure, and specifies the dialect, port, and username.
MariaDB fixtures follow the same shape but live in
TcfOss.DatabaseManager.MariaDb.IntegrationTests/DatabaseFixtures/ and use
the MariaDbBuilder/MariaDbContainer types from Testcontainers.
SQL Server (TcfOss.DatabaseManager.MsSql.IntegrationTests)¶
DatabaseFixtures/
DbFixture<TBuilder, TContainer, TContext> ← abstract; extends DbContainerFixture<,> (Testcontainers.Xunit)
FakeDbFixture ← wraps FakeDbContainer
MsSqlFixture_[Version] ← sealed; one per pinned SQL Server image tag
The SQL Server DbFixture<,,> follows the same pattern as MySQL's.
App integration tests (TcfOss.DatabaseManager.App.IntegrationTests)¶
These tests exercise the CLI end-to-end. They are organised into two test families—MySQL/MariaDB and SQL Server—each with its own fixture and test class hierarchy.
MySQL/MariaDB read-only hierarchy¶
The read-only tests verify CLI commands that do not mutate the database (parse-files, download-schema for error cases, etc.).
Fixture hierarchy¶
CliReadOnlyFixture ← non-generic abstract; IAsyncLifetime
│ Properties: IDatabaseContainer Container
│ FsProjectFixture InitialFsFixture
│
└── CliReadOnlyFixture<TBuilder, TContainer, TContext> ← generic abstract
│ Holds DbFixture<,,> (from MySql.IntegrationTests)
│ InitializeAsync: starts container, runs InitializeLibrarySchema(),
│ copies Initial schema files into InitialFsFixture
│
└── MySqlFamily/CliReadOnlyFixture_NoDatabase ← concrete; uses FakeDb (no container)
└── MySql/CliReadOnlyFixture_MySql_[Version] ← concrete; wraps MySqlFixture_[Version]
└── MariaDb/CliReadOnlyFixture_MariaDb_[Version] ← concrete; wraps MariaDbFixture_[Version]
Test class hierarchy¶
CliReadOnlyTests<TFixture> ← abstract; IClassFixture<TFixture>
│ where TFixture : CliReadOnlyFixture
│ ~1300 lines of [Fact] test methods
│ Virtual properties: Dialect, charset, collation, etc.
│
└── MySqlFamily/CliReadOnlyTests_NoDatabase ← abstract; fixes TFixture = CliReadOnlyFixture_NoDatabase
│ Overrides: ConnectionAvailable = false, DownloadSchema
│
│ └── MySql/CliReadOnlyTests_MySql_NoDatabase ← concrete; sets Dialect = MySql
│ └── MariaDb/CliReadOnlyTests_MariaDb_NoDatabase ← concrete; sets Dialect = MariaDb
│
└── MySql/CliReadOnlyTests_MySql_[Version] ← concrete; TFixture = CliReadOnlyFixture_MySql_[Version]
└── MariaDb/CliReadOnlyTests_MariaDb_[Version1] ← concrete
└── MariaDb/CliReadOnlyTests_MariaDb_[Version2] ← concrete
MySQL/MariaDB read-write hierarchy¶
The read-write tests verify commands that modify the database (apply, diff, etc.). They use a different base because each test needs a fresh container rather than a shared one.
CliReadWriteTests<TBuilder, TContainer, TContext> ← abstract; extends ContainerTest<TBuilder, TContainer>
│ (ContainerTest from Testcontainers.Xunit — provides a per-test Container instance)
│
└── MySqlFamily/CliReadWriteTests_NoDatabase ← abstract; fixes type params to FakeDb types
│
│ └── MySql/CliReadWriteTests_MySql_NoDatabase ← concrete
│ └── MariaDb/CliReadWriteTests_MariaDb_NoDatabase ← concrete
│
└── MySql/CliReadWriteTests_MySql_[Version] ← concrete
└── MariaDb/CliReadWriteTests_MariaDb_[Version1] ← concrete
└── MariaDb/CliReadWriteTests_MariaDb_[Version2] ← concrete
CliReadWriteTests inherits ContainerTest<,> directly—not IClassFixture—so the container
lifecycle is per-test, not per-class. This is intentional: read-write tests mutate the database,
so each test must start from a clean state.
SQL Server read-only hierarchy¶
SQL Server currently has only read-only tests.
Fixture hierarchy¶
MsSql/CliReadOnlyFixture_MsSql ← non-generic abstract; IAsyncLifetime
│
└── MsSql/CliReadOnlyFixture_MsSql<TBuilder, TContainer> ← generic abstract
│ Holds DbFixture<,,SysContext> (from MsSql.IntegrationTests)
│ InitializeAsync: starts container only (no schema init script)
│
└── MsSql/CliReadOnlyFixture_MsSql_FakeDb ← concrete; uses FakeDb
└── MsSql/CliReadOnlyFixture_MsSql_[Version1] ← concrete; wraps MsSqlFixture_[Version1]
└── MsSql/CliReadOnlyFixture_MsSql_[Version2] ← concrete; wraps MsSqlFixture_[Version2]
Test class hierarchy¶
MsSql/CliReadOnlyTests_MsSql<TFixture> ← abstract; IClassFixture<TFixture>
│ where TFixture : CliReadOnlyFixture_MsSql
│ [Fact] test methods for parse-files, parse errors, lex errors
│
└── MsSql/CliReadOnlyTests_MsSql_NoDatabase ← concrete; TFixture = CliReadOnlyFixture_MsSql_FakeDb
└── MsSql/CliReadOnlyTests_MsSql_[Version1] ← concrete
└── MsSql/CliReadOnlyTests_MsSql_[Version2] ← concrete
Adding a new database version¶
- Add a fixture in the relevant provider's
DatabaseFixtures/folder (e.g.MySqlFixture_[NewVersion]inTcfOss.DatabaseManager.MySql.IntegrationTests). Pin the Docker image tag inConfigure. - Add a CLI fixture in
App.IntegrationTestsunder the appropriate provider subfolder (e.g.MySql/CliReadOnlyFixture_MySql_[NewVersion]). Inherit the genericCliReadOnlyFixture<,,>orCliReadOnlyFixture_MsSql<,>and pass the new fixture toDbFixture. - Add a test class (e.g.
MySql/CliReadOnlyTests_MySql_[NewVersion]) inheritingCliReadOnlyTests<CliReadOnlyFixture_MySql_[NewVersion]>. Override dialect-specific virtual properties as needed. - For read-write tests, add a class inheriting
CliReadWriteTests<,,>, and implementConfigureto pin the image tag.
Shared namespace convention¶
The MySqlFamily/ subdirectory of App.IntegrationTests (namespace ...MySqlFamily) holds
infrastructure shared between MySQL and MariaDB that does not belong to either provider
specifically—currently the no-database fixture and abstract no-database test bases.
SQL Server shared infrastructure lives directly in MsSql/.