8.6 KiB
source_files, generated_at, model, schema_version, sha256
| source_files | generated_at | model | schema_version | sha256 | |||
|---|---|---|---|---|---|---|---|
|
2026-04-16T03:52:03.248634+00:00 | Qwen/Qwen3-Coder-Next-FP8 | 1 | b192c520f6919014 |
Utilities
Documentation: DatabaseUnitTesting.Utilities Module
1. Purpose
This module provides core infrastructure for comparing database schemas and data between two SQL Server databases as part of unit testing workflows. It enables programmatic definition of object pairs (e.g., tables or views) to compare, dynamic column exclusion, and execution of set-based data difference queries using SQL EXCEPT. The module is internal to the unit testing framework and is not intended for general-purpose database access; its primary consumers are test runners that validate expected data consistency across environments (e.g., baseline vs. modified database states).
2. Public Interface
Note
: All types and members are
internal, notpublic. They are accessible only within theDatabaseUnitTestingassembly.
ObjectsToCompare class
Represents a pair of database objects (e.g., tables) to compare, with optional column exclusions.
-
Constructor
internal ObjectsToCompare(string schema1Name, string object1Name, string schema2Name, string object2Name)Initializes a comparison pair. All arguments are non-null strings identifying the schema and object name for each side of the comparison.
-
Properties
internal string Schema1Name { get; } internal string Object1Name { get; } internal string Schema2Name { get; } internal string Object2Name { get; } internal string Qualified1 { get; } // Returns "schema1.object1" internal string Qualified2 { get; } // Returns "schema2.object2" internal IEnumerable<string> ColumnsToIgnore { get; } -
Methods
internal void AddColumnToIgnore(string columnName)Adds a column name (case-insensitive) to the list of columns to exclude from comparison.
DatabaseAdapter class
Encapsulates low-level SQL Server operations for snapshot management and database switching.
-
Constructor
internal DatabaseAdapter(SqlConnection connection)Wraps an existing
SqlConnection. Automatically opens the connection if closed. -
Methods
internal bool IsSnapshot(string name)Returns
trueifnamerefers to a database snapshot (checkssys.databases.source_database_id);falseotherwise.internal void UseDatabase(string databaseName)Executes
USE [databaseName]on the connection.internal void CreateSnapshot(string databaseName, string snapshotName)Creates a snapshot of
databaseNameat a fixed path:C:\Temp\{snapshotName}.
⚠️ Hardcoded path: AssumesC:\Temp\exists and is writable.internal void DropSnapshot(string snapshotName)Drops the snapshot
snapshotName. ThrowsArgumentExceptionif no such snapshot exists.
DatabaseComparer class
Orchestrates comparison of database objects between two databases.
-
Constructor
internal DatabaseComparer(SqlConnection connection, string databaseOneName, string databaseTwoName)Initializes the comparer. Switches the connection context to
databaseOneNameviaDatabaseAdapter.UseDatabase. -
Properties & Fields
_connection: UnderlyingSqlConnection._databaseAdapter: InternalDatabaseAdapterinstance._databaseOne,_databaseTwo: Names of the two databases being compared.
-
Methods
internal void CleanUp()Clears the list of registered object comparisons (
_objectsToCompare).internal void AddObjectComparison(string schema1, string object1, string schema2, string object2)Registers a new object pair for comparison by creating and adding an
ObjectsToCompareinstance.internal void AddColumnToIgnore(string schemaName, string objectName, string columnName)Adds a column to ignore for the first object matching
(schemaName, objectName).
⚠️ Assumes uniqueness: UsesList.Find, so only the first match is updated.internal void AddColumnsToIgnore(string schemaName, string tableName, List<string> columnNames)Adds multiple columns to ignore for the same object.
internal string GetAllColumns(SqlTransaction transaction, ObjectsToCompare objects)Queries
INFORMATION_SCHEMA.COLUMNSforobjects.Qualified1in_databaseOne.- Validates that the object exists (throws
ArgumentExceptionif not). - Removes columns listed in
objects.ColumnsToIgnore. - Throws
ArgumentExceptionif a specified column is not found or if all columns are ignored.
internal Table RunCompare(SqlTransaction transaction, ObjectsToCompare objectComparison)Executes a data comparison between
objectComparison.Qualified1andobjectComparison.Qualified2.- Uses
SELECT ... EXCEPT SELECT ...to find rows present in one side but not the other. - Adds a
TempRowNumbercolumn (viaROW_NUMBER() OVER(PARTITION BY ... ORDER BY @@SPID)) to handle duplicates. - Iterates over result sets (first = "In First", second = "In Second") to populate a
Tableobject. - Column names are normalized to lowercase in the resulting
Columnobjects.
internal Database GenerateDifferences(SqlTransaction transaction)Compares all registered objects and returns a
Databaseobject containing non-emptyTableresults.- Skips tables with zero rows in the result set.
- Validates that the object exists (throws
3. Invariants
- Object existence:
GetAllColumnsrequires that the first object (objects.Qualified1) exists in_databaseOne; otherwise, it throwsArgumentException. - Column validation: All columns passed to
AddColumnToIgnoremust exist in the target object’s column list; otherwise,GetAllColumnsthrowsArgumentException. - Non-empty comparison: At least one column must remain after ignoring columns; otherwise,
GetAllColumnsthrowsArgumentException. - Snapshot path:
CreateSnapshotassumesC:\Temp\is a valid, writable directory. - Transaction scope: All comparison queries (
RunCompare,GetAllColumns) require an activeSqlTransactionpassed explicitly. - Case sensitivity: Column names in
Columnobjects are stored in lowercase, regardless of source casing.
4. Dependencies
-
Internal dependencies:
System.Data,System.Data.SqlClient: ForSqlConnection,SqlCommand,SqlTransaction,SqlDataReader.DatabaseUnitTesting.Utilities.Results: UsesDatabase,Table,Row, andColumntypes (not included in source).
-
External dependencies:
- SQL Server (tested against versions supporting
sys.databases.source_database_id,INFORMATION_SCHEMA.COLUMNS, andEXCEPT). - File system access to
C:\Temp\for snapshot creation.
- SQL Server (tested against versions supporting
-
Consumers (inferred):
- Unit test classes (e.g.,
Microsoft.VisualStudio.TestTools.UnitTesting-based tests) that useDatabaseComparerto assert data equality.
- Unit test classes (e.g.,
5. Gotchas
- Hardcoded snapshot path:
CreateSnapshotusesC:\Temp\unconditionally. This will fail on non-Windows systems or if the directory is missing/readonly. - Ambiguous object matching:
AddColumnToIgnoreandAddColumnsToIgnoreuseList.Find, which only updates the first matchingObjectsToCompareentry. If multiple entries share the same(schema1, object1), only the first will be modified. - Case normalization: Column names are lowercased in
Row.AddColumn(...), which may cause mismatches if downstream consumers expect original casing. @@SPIDordering: TheORDER BY @@SPIDinROW_NUMBER()is arbitrary and non-deterministic. It is used solely to generate distinctTempRowNumbervalues for duplicate rows; it does not imply stable ordering.- No schema validation:
DatabaseComparerdoes not verify thatobject2exists in_databaseTwo; it assumes the object exists and will fail at query time if not. - Transaction dependency: All public comparison methods require a
SqlTransaction. Using them outside a transaction context will cause runtime errors. - No cleanup of snapshots:
DatabaseAdapterprovidesDropSnapshot, but no automatic cleanup is performed byDatabaseComparerorObjectsToCompare. Tests must explicitly manage snapshot lifecycle.
None identified beyond the above.