Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/instructions/testing.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,38 @@ Extended assertions for SqlClient:
AssertExtensions.ThrowsContains<SqlException>(() => action(), "expected message");
```

### RAII Database Object Classes
When writing manual integration tests that require transient database objects, use the RAII classes from `Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects` instead of manually writing `try/finally` blocks with DDL `DROP`/`CREATE` statements.

**Available classes:**

| Class | SQL generated | Example definition argument |
|-------|--------------|----------------------------|
| `Table` | `CREATE TABLE {Name} {definition}` | `"(Id INT, Value NVARCHAR(100))"` |
| `StoredProcedure` | `CREATE PROCEDURE {Name} {definition}` | `"AS BEGIN SELECT 1 END"` |
| `UserDefinedType` | `CREATE TYPE [dbo].{Name} AS {definition}` | `"TABLE (f1 INT)"` |

Each class generates a unique object name from the given prefix (incorporating a timestamp-based GUID, username, and machine name), creates the object on construction (requiring the connection to already be open), and drops it when disposed. The generated name is available via the `.Name` property.

**Pattern:**
```csharp
using SqlConnection conn = new(DataTestUtility.TCPConnectionString);
conn.Open();

using Table testTable = new(conn, "MyTable", "(Id INT, Name NVARCHAR(100))");
using StoredProcedure proc = new(conn, "MyProc", $"AS BEGIN SELECT * FROM {testTable.Name} END");

using SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = proc.Name;
cmd.CommandType = CommandType.StoredProcedure;
// ... objects are automatically dropped when the scope ends
```

**Rules:**
- Open the connection **before** constructing any database object (the constructor executes DDL immediately)
Comment thread
mdaigle marked this conversation as resolved.
- When objects depend on each other (e.g., a stored procedure that references a table), declare the dependent object **last** so it is disposed first — `using` declarations are disposed in reverse order
- Use the `.Name` property directly wherever you need to reference the object in SQL; for `UserDefinedType` this already includes the `[dbo].` schema prefix, making it suitable for use as a TVP `TypeName`

## Code Coverage

### Running with Coverage
Expand Down
20 changes: 18 additions & 2 deletions src/Microsoft.Data.SqlClient/tests/Common/DisposableArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,32 @@ public T this[int i]

/// <summary>
/// Disposes all elements in the current instance. Each element will be checked for
/// <c>null</c> before disposing it.
/// <c>null</c> before disposing it. All elements are disposed even if earlier disposals
/// throw; any exceptions are collected and rethrown as an <see cref="AggregateException"/>
/// after all elements have been attempted.
/// </summary>
public void Dispose()
{
List<Exception>? exceptions = null;

foreach (T element in _elements)
{
element?.Dispose();
try
{
element?.Dispose();
}
catch (Exception ex)
{
(exceptions ??= new List<Exception>()).Add(ex);
}
}

GC.SuppressFinalize(this);

if (exceptions is not null)
{
throw new AggregateException(exceptions);
}
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@
<Compile Include="SQL\MARSTest\MARSTest.cs" />
<Compile Include="SQL\MirroringTest\ConnectionOnMirroringTest.cs" />
<Compile Include="SQL\ParallelTransactionsTest\ParallelTransactionsTest.cs" />
<Compile Include="SQL\ParameterTest\DateTimeVariantTest.cs" />
<Compile Include="SQL\ParameterTest\ParametersTest.cs" />
<Compile Include="SQL\ParameterTest\SqlAdapterUpdateBatch.cs" />
<Compile Include="SQL\ParameterTest\SteAttribute.cs" />
Expand Down Expand Up @@ -262,10 +261,6 @@
CopyToOutputDirectory="PreserveNewest" />

<!-- Baseline files for individual test groups -->
<Content Include="SQL\ParameterTest\DateTimeVariant.bsl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>DateTimeVariant.bsl</Link>
</Content>
<Content Include="SQL\ParameterTest\StreamInputParameter_DebugMode.bsl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>StreamInputParameter_DebugMode.bsl</Link>
Expand Down
Loading
Loading