diff --git a/NEW/tests/JdeScoping.Database.Tests/Infrastructure/DatabaseTestBase.cs b/NEW/tests/JdeScoping.Database.Tests/Infrastructure/DatabaseTestBase.cs
new file mode 100644
index 0000000..29c0d9b
--- /dev/null
+++ b/NEW/tests/JdeScoping.Database.Tests/Infrastructure/DatabaseTestBase.cs
@@ -0,0 +1,98 @@
+using System.Text.Json;
+using Dapper;
+using JdeScoping.Core.Models.Search;
+using Microsoft.Data.SqlClient;
+
+namespace JdeScoping.Database.Tests.Infrastructure;
+
+///
+/// xUnit Collection definition to disable parallel execution for database tests.
+/// All test classes using [Collection("DatabaseTests")] run sequentially.
+///
+[CollectionDefinition("DatabaseTests")]
+public class DatabaseTestCollection : ICollectionFixture
+{
+}
+
+///
+/// Shared fixture for database tests. Ensures database is available.
+///
+public class DatabaseTestFixture : IAsyncLifetime
+{
+ ///
+ /// Connection string for the test database.
+ /// Uses SA credentials from db_info.md for local development.
+ ///
+ 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;
+}
+
+///
+/// Base class for database function tests.
+/// Each test gets its own connection and cleans up created data.
+///
+[Collection("DatabaseTests")]
+public abstract class DatabaseTestBase : IAsyncLifetime
+{
+ protected SqlConnection Connection { get; private set; } = null!;
+
+ private readonly List _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();
+ }
+
+ ///
+ /// Insert a test search with the given criteria and return the ID.
+ ///
+ protected async Task InsertTestSearchAsync(SearchCriteria criteria, string userName = "testuser", string name = "Test Search")
+ {
+ var criteriaJson = JsonSerializer.Serialize(criteria);
+
+ var id = await Connection.QuerySingleAsync(
+ @"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;
+ }
+
+ ///
+ /// Insert a test search with raw criteria JSON (for testing invalid JSON scenarios).
+ ///
+ protected async Task InsertTestSearchWithRawCriteriaAsync(string? criteriaJson, string userName = "testuser", string name = "Test Search")
+ {
+ var id = await Connection.QuerySingleAsync(
+ @"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;
+ }
+}
diff --git a/NEW/tests/JdeScoping.Database.Tests/JdeScoping.Database.Tests.csproj b/NEW/tests/JdeScoping.Database.Tests/JdeScoping.Database.Tests.csproj
index d7ef4c0..8363820 100644
--- a/NEW/tests/JdeScoping.Database.Tests/JdeScoping.Database.Tests.csproj
+++ b/NEW/tests/JdeScoping.Database.Tests/JdeScoping.Database.Tests.csproj
@@ -5,10 +5,14 @@
enable
enable
false
+ true
+
+
+
@@ -21,6 +25,7 @@
+
diff --git a/NEW/tests/JdeScoping.Database.Tests/Placeholder.cs b/NEW/tests/JdeScoping.Database.Tests/Placeholder.cs
deleted file mode 100644
index 8218846..0000000
--- a/NEW/tests/JdeScoping.Database.Tests/Placeholder.cs
+++ /dev/null
@@ -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
-}