Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.1.0 #5

Merged
merged 11 commits into from
Oct 17, 2024
2 changes: 1 addition & 1 deletion .github/workflows/github-actions-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
type: string
description: The version of the library
required: true
default: 2.0.0
default: 2.1.0
VersionSuffix:
type: string
description: The version suffix of the library (for example rc.1)
Expand Down
10 changes: 5 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="FluentAssertions" Version="6.12.1" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="5.0.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Microsoft.SqlServer.DacFx" Version="161.6374.0" />
<PackageVersion Include="Microsoft.SqlServer.DacFx" Version="162.1.172" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<PackageVersion Include="xunit" Version="2.9.1" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
</Project>
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# PosInformatique.Testing.Databases
# PosInformatique.Testing.Databases

[![NuGet Version](https://img.shields.io/nuget/v/PosInformatique.Testing.Databases.SqlServer?label=PosInformatique.Testing.Databases.SqlServer)](https://www.nuget.org/packages/PosInformatique.Testing.Databases.SqlServer)
[![NuGet Version](https://img.shields.io/nuget/v/PosInformatique.Testing.Databases.SqlServer.Dac?label=PosInformatique.Testing.Databases.SqlServer.Dac)](https://www.nuget.org/packages/PosInformatique.Testing.Databases.SqlServer.Dac)
[![NuGet Version](https://img.shields.io/nuget/v/PosInformatique.Testing.Databases.SqlServer.EntityFramework?label=PosInformatique.Testing.Databases.SqlServer.EntityFramework)](https://www.nuget.org/packages/PosInformatique.Testing.Databases.SqlServer.EntityFramework)

**PosInformatique.Testing.Databases** is a set of tools for testing databases.
It simplifies writing and executing tests, helping ensure your database and data access code are reliable and bug-free.
Expand All @@ -17,7 +21,7 @@ approach.

Since the version 2.0.0 this tools provide a comparer to compare the schema of two SQL databases.

## The approach of these tools
## 💡 The approach of these tools

The main approach of these tools is to perform tests without using mocking or in-memory alternatives for ADO .NET code or Entity Framework `DbContext`, instead using a real SQL Server database.

Expand All @@ -34,7 +38,7 @@ You also miss technical behaviors like transactions, connection management, trig
- You perform test cases, meaning you write simple tests to validate small features instead of writing complex integration tests.
- When changing the schema of the database, it is important to test and have a *safeguard* to check that the migration script (or Entity Framework migration actions) will update the database to the expected schema.

## How to test a persistence layer
## 🧪 How to test a persistence layer

To perform tests of a persistence layer, the approach is straightforward using the Arrange/Act/Assert pattern:

Expand All @@ -57,7 +61,7 @@ Before each test (`TestMethod` or `Fact` methods):

To write a test using this approach with the [PosInformatique.Testing.Databases](https://github.com/PosInformatique/PosInformatique.Testing.Databases) tools, see the [ Write tests to test the persistence layer](./docs/WriteTest.md) page.

## How to test database migration
## 🧪 How to test database migration

To perform tests of a database migration, the approach is straightforward and required only a test which perform the following actions:

Expand Down Expand Up @@ -87,7 +91,7 @@ migration code. It's better than nothing and very useful for detecting issues du

To write a test using this approach with the [PosInformatique.Testing.Databases](https://github.com/PosInformatique/PosInformatique.Testing.Databases) tools, see the [Write tests to test database migration](./docs/WriteDatabaseMigrationTest.md) page.

## What do the PosInformatique.Testing.Databases tools provide?
## 📤 What do the PosInformatique.Testing.Databases tools provide?

Using the previous approach, the [PosInformatique.Testing.Databases](https://github.com/PosInformatique/PosInformatique.Testing.Databases) libraries allow you to:

Expand All @@ -100,7 +104,7 @@ Using the previous approach, the [PosInformatique.Testing.Databases](https://git

- Contain a comparer tool to check schema differences between two databases.

## NuGet packages
## 📦 NuGet packages

The [PosInformatique.Testing.Databases](https://github.com/PosInformatique/PosInformatique.Testing.Databases) tools are provided in two NuGet packages:

Expand All @@ -115,7 +119,7 @@ The [PosInformatique.Testing.Databases](https://github.com/PosInformatique/PosIn
- [PosInformatique.Testing.Databases.SqlServer.EntityFramework](https://www.nuget.org/packages/PosInformatique.Testing.Databases.SqlServer.EntityFramework) NuGet package which contains:
- Tools to deploy a SQL Server database using a DbContext.

## Samples / Demo
## 🚀 Samples / Demo

A complete sample solution is available in this repository inside the [samples](./samples) folder.

Expand All @@ -125,7 +129,7 @@ The solution contains the following sample projects:
- [DemoApp.DataAccessLayer.Tests](./samples/DemoApp.DataAccessLayer.Tests/DemoApp.DataAccessLayer.Tests.csproj): Test project to test the [DemoApp.DataAccessLayer](./samples/DemoApp.DataAccessLayer/DemoApp.DataAccessLayer.csproj)
project using the [PosInformatique.Testing.Databases.SqlServer.EntityFramework](https://www.nuget.org/packages/PosInformatique.Testing.Databases.SqlServer.EntityFramework) package.

## Writing tests for a persistence layer
## 📝 Writing tests for a persistence layer

To write tests for a persistence layer, follow the [Write tests to test the persistence layer](./docs/WriteTest.md) documentation page, which explains the different steps to perform
using the [PosInformatique.Testing.Databases.SqlServer.EntityFramework](https://www.nuget.org/packages/PosInformatique.Testing.Databases.SqlServer.EntityFramework) library:
Expand All @@ -143,7 +147,7 @@ using the [PosInformatique.Testing.Databases.SqlServer.EntityFramework](https://
- [Execute the tests](./docs/WriteTest.md#execute-the-tests)
- [Check the database state after a test has failed](./docs/WriteTest.md#check-the-database-state-after-an-test-has-been-failed)

## Writing test to check database migration
## 📝 Writing test to check database migration

To write an test to check the migration of database, follow the [Write tests to test database migration](./docs/WriteDatabaseMigrationTest.md)
documentation page.
Expand Down
2 changes: 1 addition & 1 deletion docs/WriteDatabaseMigrationTest.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public class DatabaseMigrationTest

var targetDatabase = Task.Run(() => server.CreateDatabaseAsync(TargetDatabaseName, dbContext));

// Wait both task
// Wait both tasks
await Task.WhenAll(initialDatabase, targetDatabase);

// Call the console application to perform migration of the "DemoApp_InitialDatabase"
Expand Down
35 changes: 35 additions & 0 deletions docs/WriteTest.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,41 @@ public CustomerRepositoryTest(SqlServerDatabaseInitializer initializer)
Now, every time we will execute an test in the `CustomerRepositoryTest` class,
a database will be deployed with these 3 `Customer` before the execution of the test.

### Initializes the data from a T-SQL script

Since the version 2.1.0, it is possible to execute a T-SQL script by using the `SqlServerDatabase.ExecuteScript()` method.

For example, if we want to initialize the previous customers using a T-SQL, add a `.sql` file in the project with the following code:

```sql
INSERT INTO [Customer] ([FirstName], [LastName], [Revenue])
VALUES
('John', 'DOE', 110.50),
('Marcel', 'DUPONT', 4852.45),
('Andres', 'GARCIA', 0)
```

In Visual Studio, set the following project properties for the `InsertData.sql` file:
- `Build Action`: `Content`. This option will recompile the test project every time the T-SQL script has been changed.
- `Copy to Output Directory`: `Copy if newer`. This option allows the compiler to copy the file in the output directory and
make it available for the tests in the current directory when execution the tests.

In the constructor of the `CustomerRepositoryTest` call the script using the `SqlServerDatabase.ExecuteScript()` method.

```csharp
public CustomerRepositoryTest(SqlServerDatabaseInitializer initializer)
{
using var dbContext = new DemoAppDbContext(DatabaseTestsConnectionStrings.CreateDbContextOptions<DemoAppDbContext>(DatabaseName));

this.database = initializer.Initialize(dbContext);

this.database.ExecuteScript(File.ReadAllText("InsertData.sql"));
}
```

Now, every time we will execute an test in the `CustomerRepositoryTest` class,
a database will be deployed and the `InsertData.sql` will be executed.

## Write the tests for methods that retrieve data

This section describes how to write an test for methods that retrieve data (SELECT queries).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public CustomerRepositoryTest(SqlServerDatabaseInitializer initializer)
// Also, we recommand to force to set the IDENTITY column values explicit to avoid
// to update lot of code if you delete some rows later...
this.database.InsertCustomer(id: 20, firstName: "Andres", lastName: "GARCIA");

// - Here we use a T-SQL script to insert data in the Customer table.
// The script can contains GO instructions.
this.database.ExecuteScript(File.ReadAllText("InsertData.sql"));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
Expand All @@ -9,6 +9,16 @@
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<None Remove="InsertData.sql" />
</ItemGroup>

<ItemGroup>
<Content Include="InsertData.sql">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" />
<PackageReference Include="FluentAssertions" />
Expand Down
4 changes: 4 additions & 0 deletions samples/DemoApp.DataAccessLayer.Tests/InsertData.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
INSERT INTO [Customer] ([FirstName], [LastName], [Revenue])
VALUES ('From script', 'Peter', 100)

GO 10 -- Execute the previous insert 10x times.
10 changes: 5 additions & 5 deletions samples/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="FluentAssertions" Version="6.12.1" />
<PackageVersion Include="Microsoft.Data.SqlClient" Version="5.0.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Microsoft.SqlServer.DacFx" Version="161.6374.0" />
<PackageVersion Include="PosInformatique.Testing.Databases.SqlServer.EntityFramework" Version="2.0.0-rc.1" />
<PackageVersion Include="PosInformatique.Testing.Databases.SqlServer.EntityFramework" Version="2.1.0-rc.3" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<PackageVersion Include="xunit" Version="2.9.1" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
</Project>
24 changes: 19 additions & 5 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,25 @@
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReleaseNotes>
1.0.1
- Fix the documentation

1.0.0
- Initial version
2.1.0
- PosInformatique.Testing.Databases.SqlServer target the .NET Standard 2.0 platform.
- PosInformatique.Testing.Databases.SqlServer.Dac target the .NET Core 6.0 and .NET Framework 4.6.2
- PosInformatique.Testing.Databases.SqlServer.EntityFramework target the .NET Core 6.0
- Reduce the dependencies to Entity Framework 6.0
- Reduce the dependencies of DACfx to a more earlier version.
- Add new method SqlServerDatabase.ExecuteScript() to execute T-SQL scripts.

2.0.0
- Add SqlServerDatabaseComparer class to perform comparison between two databases.
- Add new PosInformatique.Testing.Databases.SqlServer.Dac NuGet package which contains DAC package tools.
- Add new SqlServer.CreateDatabaseAsync() extension method to create a database from a DbContext.
- Reduce dependencies version of the Entity Framework Core and SQL Server Client NuGet packages.

1.0.1
- Fix the documentation

1.0.0
- Initial version
</PackageReleaseNotes>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFrameworks>net6.0;net462</TargetFrameworks>

<Description>Testing.Databases.SqlServer.Dac is a library that contains a set of tools for testing to deploy DAC (Data-tier Applications) packages (.dacpac files).</Description>
<PackageTags>testing unittest sqlserver repository tdd dataaccesslayer dacpac dac</PackageTags>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<GenerateDocumentationFile>True</GenerateDocumentationFile>

<Description>Testing.Databases.SqlServer.EntityFramework is a library that contains a set of tools for testing Data Access Layer (repositories) based on Entity Framework and SQL Server.</Description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,37 @@ namespace PosInformatique.Testing.Databases
/// </summary>
public class SqlDatabaseComparisonResults
{
internal SqlDatabaseComparisonResults()
internal SqlDatabaseComparisonResults(
IList<SqlObjectDifferences<SqlStoredProcedure>> storedProcedures,
IList<SqlTableDifferences> tables,
IList<SqlObjectDifferences<SqlUserType>> userTypes,
IList<SqlObjectDifferences<SqlView>> views)
{
this.StoredProcedures = new ReadOnlyCollection<SqlObjectDifferences<SqlStoredProcedure>>(storedProcedures);
this.Tables = new ReadOnlyCollection<SqlTableDifferences>(tables);
this.UserTypes = new ReadOnlyCollection<SqlObjectDifferences<SqlUserType>>(userTypes);
this.Views = new ReadOnlyCollection<SqlObjectDifferences<SqlView>>(views);
}

/// <summary>
/// Gets the stored procedures which are different between two databases.
/// </summary>
public required ReadOnlyCollection<SqlObjectDifferences<SqlStoredProcedure>> StoredProcedures { get; init; }
public ReadOnlyCollection<SqlObjectDifferences<SqlStoredProcedure>> StoredProcedures { get; }

/// <summary>
/// Gets the tables which are different between two databases.
/// </summary>
public required ReadOnlyCollection<SqlTableDifferences> Tables { get; init; }
public ReadOnlyCollection<SqlTableDifferences> Tables { get; }

/// <summary>
/// Gets the user types which are different between two databases.
/// </summary>
public required ReadOnlyCollection<SqlObjectDifferences<SqlUserType>> UserTypes { get; init; }
public ReadOnlyCollection<SqlObjectDifferences<SqlUserType>> UserTypes { get; }

/// <summary>
/// Gets the views which are different between two databases.
/// </summary>
public required ReadOnlyCollection<SqlObjectDifferences<SqlView>> Views { get; init; }
public ReadOnlyCollection<SqlObjectDifferences<SqlView>> Views { get; }

/// <summary>
/// Gets a value indicating whether if the two database compared have the same schema.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ private void WriteLine()

private void WriteLine(string value)
{
var lines = value.Split(Environment.NewLine);
var lines = value.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

if (lines.Length > 1)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ internal SqlObjectDifferences(TSqlObject? source, TSqlObject? target, SqlObjectD
/// <summary>
/// Gets the property changes between <see cref="Source"/> and <see cref="Target"/>.
/// </summary>
public ReadOnlyCollection<SqlObjectPropertyDifference> Properties { get; init; }
public ReadOnlyCollection<SqlObjectPropertyDifference> Properties { get; }

/// <summary>
/// Returns a textual representation of the result comparison.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,7 @@ await Task.WhenAll(
var userTypesDifferences = SqlObjectComparer.Compare(sourceUserTypes.Result, targetUserTypes.Result, ut => ut.Name);
var viewsDifferences = SqlObjectComparer.Compare(sourceViews.Result, targetViews.Result, v => v.Schema + "." + v.Name);

return new SqlDatabaseComparisonResults()
{
StoredProcedures = new ReadOnlyCollection<SqlObjectDifferences<SqlStoredProcedure>>(storedProceduresDifferences),
Tables = new ReadOnlyCollection<SqlTableDifferences>(tablesDifferences),
UserTypes = new ReadOnlyCollection<SqlObjectDifferences<SqlUserType>>(userTypesDifferences),
Views = new ReadOnlyCollection<SqlObjectDifferences<SqlView>>(viewsDifferences),
};
return new SqlDatabaseComparisonResults(storedProceduresDifferences, tablesDifferences, userTypesDifferences, viewsDifferences);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ internal SqlTableDifferences(
/// <summary>
/// Gets the primary key differences between the two SQL tables.
/// </summary>
public required SqlPrimaryKeyDifferences? PrimaryKey { get; init; }
public SqlPrimaryKeyDifferences? PrimaryKey { get; internal set; }

/// <summary>
/// Gets the foreign keys differences between the two SQL tables.
Expand Down
2 changes: 1 addition & 1 deletion src/Testing.Databases.SqlServer/Comparer/TsqlCodeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal static class TsqlCodeHelper
}

return code
.ReplaceLineEndings(string.Empty)
.Replace(Environment.NewLine, string.Empty)
.Replace(" ", string.Empty)
.Replace("\t", string.Empty);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,21 @@ namespace PosInformatique.Testing.Databases
/// </summary>
public sealed class SqlCheckConstraint : SqlObject
{
internal SqlCheckConstraint()
internal SqlCheckConstraint(string name, string code)
{
this.Name = name;
this.Code = code;
}

/// <summary>
/// Gets the name of the check constraint type.
/// </summary>
public required string Name { get; init; }
public string Name { get; }

/// <summary>
/// Gets the code of the check constraint.
/// </summary>
public required string Code { get; init; }
public string Code { get; }

/// <inheritdoc />
public override TResult Accept<TResult>(ISqlObjectVisitor<TResult> visitor) => visitor.Visit(this);
Expand Down
Loading
Loading