Home

Awesome

<img src="/src/icon.png" height="30px"> Verify.SqlServer

Discussions Build status NuGet Status

Extends Verify to allow verification of SqlServer bits.

See Milestones for release notes.

NuGet package

https://nuget.org/packages/Verify.SqlServer/

Usage

<!-- snippet: Enable -->

<a id='snippet-Enable'></a>

[ModuleInitializer]
public static void Init() =>
    VerifySqlServer.Initialize();

<sup><a href='/src/Tests/ModuleInit.cs#L3-L9' title='Snippet source file'>snippet source</a> | <a href='#snippet-Enable' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

SqlServer Schema

This test:

<!-- snippet: SqlServerSchema -->

<a id='snippet-SqlServerSchema'></a>

await Verify(connection);

<sup><a href='/src/Tests/Tests.cs#L84-L88' title='Snippet source file'>snippet source</a> | <a href='#snippet-SqlServerSchema' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Will result in the following verified file:

<pre> <!-- emptyInclude: Tests.Schema.verified.md --> </pre>

Object types to include

<!-- snippet: SchemaInclude -->

<a id='snippet-SchemaInclude'></a>

await Verify(connection)
    // include only tables and views
    .SchemaIncludes(DbObjects.Tables | DbObjects.Views);

<sup><a href='/src/Tests/Tests.cs#L390-L396' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaInclude' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Available values:

<!-- snippet: DbObjects.cs -->

<a id='snippet-DbObjects.cs'></a>

namespace VerifyTests.SqlServer;

[Flags]
public enum DbObjects
{
    StoredProcedures = 1,
    Synonyms = 2,
    Tables = 4,
    UserDefinedFunctions = 8,
    Views = 16,
    All = StoredProcedures | Synonyms | Tables | UserDefinedFunctions | Views
}

<sup><a href='/src/Verify.SqlServer/SchemaValidation/DbObjects.cs#L1-L12' title='Snippet source file'>snippet source</a> | <a href='#snippet-DbObjects.cs' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Filtering

Objects can be dynamically filtered:

<!-- snippet: SchemaFilter -->

<a id='snippet-SchemaFilter'></a>

await Verify(connection)
    // include tables & views, or named MyTrigger
    .SchemaFilter(
        _ => _ is TableViewBase ||
             _.Name == "MyTrigger");

<sup><a href='/src/Tests/Tests.cs#L415-L423' title='Snippet source file'>snippet source</a> | <a href='#snippet-SchemaFilter' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Recording

Recording allows all commands executed to be captured and then (optionally) verified.

Call SqlRecording.StartRecording():

<!-- snippet: Recording -->

<a id='snippet-Recording'></a>

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
Recording.Start();
await using var command = connection.CreateCommand();
command.CommandText = "select Value from MyTable";
var value = await command.ExecuteScalarAsync();
await Verify(value!);

<sup><a href='/src/Tests/Tests.cs#L199-L209' title='Snippet source file'>snippet source</a> | <a href='#snippet-Recording' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Will result in the following verified file:

<!-- snippet: Tests.RecordingUsage.verified.txt -->

<a id='snippet-Tests.RecordingUsage.verified.txt'></a>

{
  target: 42,
  sql: {
    Text: select Value from MyTable,
    HasTransaction: false
  }
}

<sup><a href='/src/Tests/Tests.RecordingUsage.verified.txt#L1-L7' title='Snippet source file'>snippet source</a> | <a href='#snippet-Tests.RecordingUsage.verified.txt' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Sql entries can be explicitly read using SqlRecording.FinishRecording, optionally filtered, and passed to Verify:

<!-- snippet: RecordingSpecific -->

<a id='snippet-RecordingSpecific'></a>

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
Recording.Start();
await using var command = connection.CreateCommand();
command.CommandText = "select Value from MyTable";
var value = await command.ExecuteScalarAsync();

await using var errorCommand = connection.CreateCommand();
errorCommand.CommandText = "select Value from BadTable";
try
{
    await errorCommand.ExecuteScalarAsync();
}
catch
{
}

var entries = Recording
    .Stop()
    .Select(_ => _.Data);
//Optionally filter results
await Verify(
    new
    {
        value,
        sqlEntries = entries
    });

<sup><a href='/src/Tests/Tests.cs#L276-L306' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingSpecific' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Interpreting recording results

Recording results can be interpreted in a a variety of ways:

<!-- snippet: RecordingReadingResults -->

<a id='snippet-RecordingReadingResults'></a>

var entries = Recording.Stop();

// all sql entries via key
var sqlEntries = entries
    .Where(_ => _.Name == "sql")
    .Select(_ => _.Data);

// successful Commands via Type
var sqlCommandsViaType = entries
    .Select(_ => _.Data)
    .OfType<SqlCommand>();

// failed Commands via Type
var sqlErrorsViaType = entries
    .Select(_ => _.Data)
    .OfType<ErrorEntry>();

<sup><a href='/src/Tests/Tests.cs#L332-L351' title='Snippet source file'>snippet source</a> | <a href='#snippet-RecordingReadingResults' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Icon

Database designed by Creative Stall from The Noun Project.