feat(tests): add database test infrastructure
Add DatabaseTestBase.cs with xUnit Collection for test isolation: - DatabaseTestCollection disables parallel execution - DatabaseTestFixture verifies database connectivity - DatabaseTestBase provides connection and cleanup helpers - InsertTestSearchAsync for creating test data with SearchCriteria - InsertTestSearchWithRawCriteriaAsync for testing invalid JSON scenarios Also adds required packages: Dapper, FluentAssertions, Microsoft.Data.SqlClient
This commit is contained in:
@@ -0,0 +1,98 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Dapper;
|
||||||
|
using JdeScoping.Core.Models.Search;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
|
namespace JdeScoping.Database.Tests.Infrastructure;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// xUnit Collection definition to disable parallel execution for database tests.
|
||||||
|
/// All test classes using [Collection("DatabaseTests")] run sequentially.
|
||||||
|
/// </summary>
|
||||||
|
[CollectionDefinition("DatabaseTests")]
|
||||||
|
public class DatabaseTestCollection : ICollectionFixture<DatabaseTestFixture>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shared fixture for database tests. Ensures database is available.
|
||||||
|
/// </summary>
|
||||||
|
public class DatabaseTestFixture : IAsyncLifetime
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Connection string for the test database.
|
||||||
|
/// Uses SA credentials from db_info.md for local development.
|
||||||
|
/// </summary>
|
||||||
|
public const string ConnectionString =
|
||||||
|
"Server=localhost,1434;Database=ScopingTool;User Id=sa;Password=ScopingTool_SA_2024Dev;TrustServerCertificate=true";
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
// Verify database is accessible
|
||||||
|
using var connection = new SqlConnection(ConnectionString);
|
||||||
|
await connection.OpenAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DisposeAsync() => Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for database function tests.
|
||||||
|
/// Each test gets its own connection and cleans up created data.
|
||||||
|
/// </summary>
|
||||||
|
[Collection("DatabaseTests")]
|
||||||
|
public abstract class DatabaseTestBase : IAsyncLifetime
|
||||||
|
{
|
||||||
|
protected SqlConnection Connection { get; private set; } = null!;
|
||||||
|
|
||||||
|
private readonly List<int> _createdSearchIds = [];
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
Connection = new SqlConnection(DatabaseTestFixture.ConnectionString);
|
||||||
|
await Connection.OpenAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisposeAsync()
|
||||||
|
{
|
||||||
|
// Clean up test data
|
||||||
|
foreach (var id in _createdSearchIds)
|
||||||
|
{
|
||||||
|
await Connection.ExecuteAsync("DELETE FROM dbo.Search WHERE ID = @Id", new { Id = id });
|
||||||
|
}
|
||||||
|
|
||||||
|
await Connection.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Insert a test search with the given criteria and return the ID.
|
||||||
|
/// </summary>
|
||||||
|
protected async Task<int> InsertTestSearchAsync(SearchCriteria criteria, string userName = "testuser", string name = "Test Search")
|
||||||
|
{
|
||||||
|
var criteriaJson = JsonSerializer.Serialize(criteria);
|
||||||
|
|
||||||
|
var id = await Connection.QuerySingleAsync<int>(
|
||||||
|
@"INSERT INTO dbo.Search (UserName, Name, Status, Criteria)
|
||||||
|
OUTPUT INSERTED.ID
|
||||||
|
VALUES (@UserName, @Name, 0, @Criteria)",
|
||||||
|
new { UserName = userName, Name = name, Criteria = criteriaJson });
|
||||||
|
|
||||||
|
_createdSearchIds.Add(id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Insert a test search with raw criteria JSON (for testing invalid JSON scenarios).
|
||||||
|
/// </summary>
|
||||||
|
protected async Task<int> InsertTestSearchWithRawCriteriaAsync(string? criteriaJson, string userName = "testuser", string name = "Test Search")
|
||||||
|
{
|
||||||
|
var id = await Connection.QuerySingleAsync<int>(
|
||||||
|
@"INSERT INTO dbo.Search (UserName, Name, Status, Criteria)
|
||||||
|
OUTPUT INSERTED.ID
|
||||||
|
VALUES (@UserName, @Name, 0, @Criteria)",
|
||||||
|
new { UserName = userName, Name = name, Criteria = criteriaJson });
|
||||||
|
|
||||||
|
_createdSearchIds.Add(id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,10 +5,14 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||||
|
<PackageReference Include="Dapper" Version="2.1.35" />
|
||||||
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
<PackageReference Include="NSubstitute" Version="5.3.0" />
|
||||||
<PackageReference Include="Shouldly" Version="4.3.0" />
|
<PackageReference Include="Shouldly" Version="4.3.0" />
|
||||||
@@ -21,6 +25,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\JdeScoping.Core\JdeScoping.Core.csproj" />
|
||||||
<ProjectReference Include="..\..\src\JdeScoping.Database\JdeScoping.Database.csproj" />
|
<ProjectReference Include="..\..\src\JdeScoping.Database\JdeScoping.Database.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
// This file exists to ensure the test project compiles.
|
|
||||||
// Add tests here as needed.
|
|
||||||
namespace JdeScoping.Database.Tests;
|
|
||||||
|
|
||||||
public class Placeholder
|
|
||||||
{
|
|
||||||
// Tests will be added here
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user