Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 8 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
<PackageVersion Include="BenchmarkDotNet" Version="0.15.0" />
<PackageVersion Include="MartinCostello.SqlLocalDb" Version="4.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.5" />
<PackageVersion Include="Respawn" Version="6.2.1" />
<PackageVersion Include="Testcontainers.MsSql" Version="4.5.0" />
<PackageVersion Include="Polyfill" Version="7.33.0" />
<PackageVersion Include="FluentAssertions" Version="7.2.0" />
Expand All @@ -38,6 +37,14 @@
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
</ItemGroup>

<ItemGroup Label="Test projects dependencies NET FX" Condition=" '$(TargetFramework)' == 'net472' ">
<PackageVersion Include="Respawn" Version="4.0.0" />
</ItemGroup>

<ItemGroup Label="Test projects dependencies NET 9" Condition=" '$(TargetFramework)' == 'net9.0' ">
<PackageVersion Include="Respawn" Version="6.2.1" />
</ItemGroup>

<ItemGroup Label="Sample projects dependencies">
<PackageVersion Include="AutoMapper" Version="14.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.5" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MartinCostello.SqlLocalDb"/>
<PackageReference Include="EntityFramework"/>
<PackageReference Include="System.Data.DataSetExtensions"/>
<PackageReference Include="Testcontainers.MsSql"/>
<PackageReference Include="Microsoft.CSharp"/>
<PackageReference Include="MartinCostello.SqlLocalDb" />
<PackageReference Include="EntityFramework" />
<PackageReference Include="Respawn" />
<PackageReference Include="System.Data.DataSetExtensions" />
<PackageReference Include="Testcontainers.MsSql" />
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="Polyfill">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations.Schema;

namespace Tests.FixtureNew;

public record Address
{
public int Id { get; set; }
public string? Street { get; set; }

public Store Store { get; set; } = default!;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations.Schema;

namespace Tests.FixtureNew;

public record Company
{
public int Id { get; set; }
public required string Name { get; set; }

public int CountryId { get; set; }
public Country Country { get; set; } = default!;

public List<Store> Stores { get; set; } = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Tests.FixtureNew;

public record Country
{
public int Id { get; set; }
public int No { get; set; }
public string? Name { get; set; }
public bool IsDeleted { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Tests.FixtureNew;

public record Product
{
public int Id { get; set; }
public string? Name { get; set; }

public int StoreId { get; set; }
public Store Store { get; set; } = default!;

public List<ProductImage>? Images { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Tests.FixtureNew;

public record ProductImage
{
public int Id { get; set; }
public string? ImageUrl { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; } = default!;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Tests.FixtureNew;

public record Store
{
public int Id { get; set; }
public string? Name { get; set; }
public string? City { get; set; }

public int CompanyId { get; set; }
public Company Company { get; set; } = default!;

public Address Address { get; set; } = default!;

public List<Product> Products { get; set; } = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Collections;

namespace Tests.FixtureNew;

public class IntegrationTest : IAsyncLifetime
{
protected TestDbContext DbContext { get; private set; } = default!;
private readonly TestFactory _testFactory;

public IntegrationTest(TestFactory testFactory)
{
_testFactory = testFactory;
}

public Task InitializeAsync()
{
DbContext = new TestDbContext(_testFactory.ConnectionString);
return Task.CompletedTask;
}

public async Task DisposeAsync()
{
DbContext.Dispose();
await _testFactory.ResetDatabase();
}

public async Task SeedAsync<TEntity>(TEntity entity) where TEntity : class
{
using var dbContext = new TestDbContext(_testFactory.ConnectionString);
dbContext.Set<TEntity>().Add(entity);
await dbContext.SaveChangesAsync();
}

public async Task SeedRangeAsync<TEntity>(TEntity[] entities) where TEntity : class
{
using var dbContext = new TestDbContext(_testFactory.ConnectionString);
dbContext.Set<TEntity>().AddRange(entities);
await dbContext.SaveChangesAsync();
}

public async Task SeedRangeAsync(IEnumerable entities)
{
using var dbContext = new TestDbContext(_testFactory.ConnectionString);
foreach (var entity in entities)
{
dbContext.Set(entity.GetType()).Add(entity);
}
await dbContext.SaveChangesAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Tests.FixtureNew;

public class Repository<T>(TestDbContext context) : RepositoryBase<T>(context) where T : class
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Tests.FixtureNew;

[CollectionDefinition("SharedCollection")]
public class SharedCollection : ICollectionFixture<TestFactory>
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Data.Entity;

namespace Tests.FixtureNew;

public class TestDbContext : DbContext
{
public TestDbContext(string connectionString) : base(connectionString)
{
}

public DbSet<Country> Countries => Set<Country>();
public DbSet<Company> Companies => Set<Company>();
public DbSet<Store> Stores => Set<Store>();
public DbSet<Address> Addresses => Set<Address>();
public DbSet<Product> Products => Set<Product>();

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Store-Address one-to-one (Address has StoreId FK)
modelBuilder.Entity<Store>()
.HasOptional(s => s.Address)
.WithRequired(a => a.Store)
.Map(m => m.MapKey("StoreId"));

// Country-Company one-to-many (Company has CountryId FK)
modelBuilder.Entity<Company>()
.HasRequired(co => co.Country)
.WithMany()
.HasForeignKey(co => co.CountryId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using MartinCostello.SqlLocalDb;
using Testcontainers.MsSql;
using Respawn;

namespace Tests.FixtureNew;

public class TestFactory : IAsyncLifetime
{
// Flag to force using Docker SQL Server. Update it manually if you want to avoid localDb locally.
private const bool FORCE_DOCKER = false;

private string _connectionString = default!;
private MsSqlContainer? _dbContainer = null;

public string ConnectionString => _connectionString;
public TestDbContext DbContext => new TestDbContext(_connectionString);

#if NET9_0_OR_GREATER
private Respawner _respawner = default!;
public async Task ResetDatabase() => await _respawner.ResetAsync(_connectionString);
#elif NET472
private Checkpoint _respawner = default!;
public Task ResetDatabase() => _respawner.Reset(_connectionString);
#endif

public async Task InitializeAsync()
{
using (var localDB = new SqlLocalDbApi())
{
if (FORCE_DOCKER || !localDB.IsLocalDBInstalled())
{
_dbContainer = CreateContainer();
await _dbContainer.StartAsync();
_connectionString = _dbContainer.GetConnectionString();
}
else
{
#if NET9_0_OR_GREATER
_connectionString = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=SpecificationTestsDB_EF6_NET9;Integrated Security=SSPI;TrustServerCertificate=True;";
#elif NET472

_connectionString = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=SpecificationTestsDB_EF6_NETFFX;Integrated Security=SSPI;TrustServerCertificate=True;";
#endif
}
}

Console.WriteLine($"Connection string: {_connectionString}");

using (var dbContext = new TestDbContext(_connectionString))
{
//dbContext.Database.Delete();
dbContext.Database.CreateIfNotExists();
}

#if NET9_0_OR_GREATER
_respawner = await Respawner.CreateAsync(_connectionString, new RespawnerOptions
{
DbAdapter = DbAdapter.SqlServer,
SchemasToInclude = new[] { "dbo" },
});
await ResetDatabase();
#elif NET472
_respawner = new Checkpoint
{
DbAdapter = DbAdapter.SqlServer,
SchemasToInclude = new[] { "dbo" },
};
await ResetDatabase();
#endif
}

public async Task DisposeAsync()
{
if (_dbContainer is not null)
{
await _dbContainer.StopAsync();
}
else
{
//using var dbContext = new TestDbContext(_connectionString);
//dbContext.Database.Delete();
}
}

private static MsSqlContainer CreateContainer() => new MsSqlBuilder()
.WithImage("mcr.microsoft.com/mssql/server:2022-latest")
.WithPassword("P@ssW0rd!")
.Build();
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading.Tasks;
global using Tests.Fixture;
global using Xunit;
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Tests;
using Tests.Fixture;

namespace Tests;

[Collection("ReadCollection")]
public class RepositoryOfT_AnyAsync
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Tests;
using Tests.Fixture;

namespace Tests;

[Collection("WriteCollection")]
public class RepositoryOfT_DeleteRangeAsync
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Tests;
using Tests.Fixture;

namespace Tests;

[Collection("ReadCollection")]
public class RepositoryOfT_GetById
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Data.Entity;
using Tests.Fixture;
using System.Data.Entity;

namespace Tests;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Tests;
using Tests.Fixture;

namespace Tests;

[Collection("ReadCollection")]
public class RepositoryOfT_ListAsync
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public async Task InitializeAsync()
}
else
{
_connectionString = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=SpecificationEFCoreTestsDB;Integrated Security=SSPI;TrustServerCertificate=True;";
_connectionString = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=SpecificationTestsDB_EFCore;Integrated Security=SSPI;TrustServerCertificate=True;";
}
}

Expand Down Expand Up @@ -70,7 +70,7 @@ public async Task DisposeAsync()

private static MsSqlContainer CreateContainer() => new MsSqlBuilder()
.WithImage("mcr.microsoft.com/mssql/server:2022-latest")
.WithName("SpecificationEFCoreTestsDB")
.WithName("SpecificationTestsDB_EFCore")
.WithPassword("P@ssW0rd!")
.Build();
}