From fe71997c0bf702e7cee5d3abb4843d3a8aa0f29a Mon Sep 17 00:00:00 2001
From: Simon Geering <25039878+SimonGeering@users.noreply.github.com>
Date: Thu, 8 Apr 2021 16:35:20 +0100
Subject: [PATCH] #167 Updated IntegrationTestBase and DbContext SeedData code
to allow the Respawn NuGet package to clear down Currency and BankAccount
seed data and re-populate it when running tests.
---
.../EntityFramework/Model/AccountsSchema.cs | 33 ++++++--
.../DAL/EntityFramework/Model/CoreSchema.cs | 33 ++++++--
.../IntegrationTestBase.cs | 82 +++++++++++++------
3 files changed, 109 insertions(+), 39 deletions(-)
diff --git a/src/AdminAssistant.Infra/DAL/EntityFramework/Model/AccountsSchema.cs b/src/AdminAssistant.Infra/DAL/EntityFramework/Model/AccountsSchema.cs
index 08e6bb3e..bf8b6292 100644
--- a/src/AdminAssistant.Infra/DAL/EntityFramework/Model/AccountsSchema.cs
+++ b/src/AdminAssistant.Infra/DAL/EntityFramework/Model/AccountsSchema.cs
@@ -4,10 +4,33 @@
namespace AdminAssistant.Infra.DAL.EntityFramework.Model
{
- internal class AccountsSchema
+ public static class AccountsSchema
{
private const string Name = "Accounts";
+ /// Sets up static lookup data for the accounts module.
+ ///
+ /// This is used both in the EF Core migrations for the prod DB as well as functional acceptance and integration
+ /// tests. In the latter case, it simulate migrations having been run, because the `Respawn` NuGet package
+ /// clears down the DB to blank between each test execution.
+ ///
+ /// `True` for EF Core migration code otherwise `False`.
+ /// Out of the box default bank account types.
+ public static BankAccountTypeEntity[] GetBankAccountTypesSeedData(bool includeIDs = false)
+ {
+ var currentAccount = new BankAccountTypeEntity() { Description = "Current Account", AllowCompany = true, AllowPersonal = true };
+ if (includeIDs) currentAccount.BankAccountTypeID = 1;
+
+ var savingsAccount = new BankAccountTypeEntity() { Description = "Savings Account", AllowCompany = true, AllowPersonal = true };
+ if (includeIDs) savingsAccount.BankAccountTypeID = 2;
+
+ return new BankAccountTypeEntity[]
+ {
+ currentAccount,
+ savingsAccount
+ };
+ }
+
internal static void OnModelCreating(ModelBuilder builder)
{
AccountsSchema.Bank_OnModelCreating(builder);
@@ -53,12 +76,8 @@ private static void BankAccountType_OnModelCreating(ModelBuilder builder)
builder.Entity().Property(x => x.AllowCompany).IsRequired().HasDefaultValue(false);
builder.Entity().Property(x => x.IsDeprecated).IsRequired().HasDefaultValue(false);
- builder.Entity().HasData(new BankAccountTypeEntity[]
- {
- new BankAccountTypeEntity() { BankAccountTypeID = 1, Description = "Current Account", AllowCompany = true, AllowPersonal = true },
- new BankAccountTypeEntity() { BankAccountTypeID = 2, Description = "Savings Account", AllowCompany = true, AllowPersonal = true },
- });
- }
+ builder.Entity().HasData(GetBankAccountTypesSeedData(true));
+ }
private static void Payee_OnModelCreating(ModelBuilder builder)
{
diff --git a/src/AdminAssistant.Infra/DAL/EntityFramework/Model/CoreSchema.cs b/src/AdminAssistant.Infra/DAL/EntityFramework/Model/CoreSchema.cs
index 1375fc46..0ee29846 100644
--- a/src/AdminAssistant.Infra/DAL/EntityFramework/Model/CoreSchema.cs
+++ b/src/AdminAssistant.Infra/DAL/EntityFramework/Model/CoreSchema.cs
@@ -4,10 +4,34 @@
namespace AdminAssistant.Infra.DAL.EntityFramework.Model.Core
{
- internal class CoreSchema
+ public static class CoreSchema
{
private const string Name = "Core";
+ /// Sets up static lookup data for the core module.
+ ///
+ /// This is used both in the EF Core migrations for the prod DB as well as functional acceptance and integration
+ /// tests. In the latter case, it simulate migrations having been run, because the `Respawn` NuGet package
+ /// clears down the DB to blank between each test execution.
+ ///
+ /// `True` for EF Core migration code otherwise `False`.
+ /// Out of the box default currencies.
+ public static CurrencyEntity[] GetCurrencySeedData(bool includeIDs = false)
+ {
+ const string defaultDecimalFormat = "2.2-2";
+
+ var GBP = new CurrencyEntity { Symbol = "GBP", DecimalFormat = defaultDecimalFormat };
+ if (includeIDs) GBP.CurrencyID = 1;
+
+ var EUR = new CurrencyEntity { Symbol = "EUR", DecimalFormat = defaultDecimalFormat };
+ if (includeIDs) EUR.CurrencyID = 2;
+
+ var USD = new CurrencyEntity { Symbol = "USD", DecimalFormat = defaultDecimalFormat };
+ if (includeIDs) USD.CurrencyID = 3;
+
+ return new CurrencyEntity[] { GBP, EUR, USD };
+ }
+
internal static void OnModelCreating(ModelBuilder modelBuilder)
{
CoreSchema.Audit_OnModelCreating(modelBuilder);
@@ -76,12 +100,7 @@ private static void Currency_OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity().Property(x => x.Symbol).IsRequired().IsUnicode().HasMaxLength(Currency.SymbolMaxLength).HasColumnType($"CHAR({Currency.SymbolMaxLength})");
modelBuilder.Entity().Property(x => x.DecimalFormat).IsRequired().HasMaxLength(Currency.DecimalFormatMaxLength).HasColumnType($"CHAR({Currency.DecimalFormatMaxLength})");
modelBuilder.Entity().Property(x => x.IsDeprecated).IsRequired().HasDefaultValue(false);
- modelBuilder.Entity().HasData(new CurrencyEntity[]
- {
- new CurrencyEntity { CurrencyID = 1, Symbol = "GBP", DecimalFormat = "2.2-2" },
- new CurrencyEntity { CurrencyID = 2, Symbol = "EUR", DecimalFormat = "2.2-2" },
- new CurrencyEntity { CurrencyID = 3, Symbol = "USD", DecimalFormat = "2.2-2" },
- });
+ modelBuilder.Entity().HasData(GetCurrencySeedData(true));
}
private static void Owner_OnModelCreating(ModelBuilder modelBuilder)
diff --git a/src/AdminAssistant.Test/IntegrationTestBase.cs b/src/AdminAssistant.Test/IntegrationTestBase.cs
index 134cfba5..d8efd4c5 100644
--- a/src/AdminAssistant.Test/IntegrationTestBase.cs
+++ b/src/AdminAssistant.Test/IntegrationTestBase.cs
@@ -1,10 +1,13 @@
#if DEBUG // quick and dirty fix for #85 category filtering breaking CI Unit Test run.
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using AdminAssistant.Infra.DAL.EntityFramework;
+using AdminAssistant.Infra.DAL.EntityFramework.Model;
+using AdminAssistant.Infra.DAL.EntityFramework.Model.Accounts;
using AdminAssistant.Infra.DAL.EntityFramework.Model.Core;
using AdminAssistant.Infra.Providers;
using AdminAssistant.UI.Shared.WebAPIClient.v1;
@@ -69,9 +72,7 @@ public IntegrationTestBase()
{
"sysdiagrams",
"__EFMigrationsHistory",
- "tblObjectType",
- "Currency",
- "BankAccountType"
+ "tblObjectType"
},
WithReseed = true
};
@@ -90,17 +91,55 @@ protected async Task ResetDatabaseAsync()
var dbContext = Container.GetRequiredService();
var dateTimeProvider = Container.GetRequiredService();
- // TODO: Replace this with IUserProfileRepository when it exists ...
+ var testBankAccountTypes = await SeedBankAccountTypeTestData(dbContext);
+ var testCurrencies = await SeedCurrencyTestData(dbContext);
+ var testUserProfile = await SeedUserProfileTestData(dbContext, dateTimeProvider).ConfigureAwait(false);
+ var testCompanyOwner = await SeedCompanyOwnerTestData(dbContext, dateTimeProvider, testUserProfile).ConfigureAwait(false);
+ var testPersonalOwner = await SeedPersonalOwnerTestData(dbContext, dateTimeProvider, testUserProfile).ConfigureAwait(false);
+ }
+
+ protected virtual Action ConfigureTestServices() => services =>
+ {
+ // Register the WebAPIClient using the test httpClient ...
+ services.AddTransient((sp) =>
+ {
+ Guard.Against.Null(_httpClient.BaseAddress, "httpClient.BaseAddress");
+ return new AdminAssistantWebAPIClient(_httpClient) { BaseUrl = _httpClient.BaseAddress.ToString() };
+ });
+ services.AddAutoMapper(typeof(MappingProfile));
+ };
+
+ private async Task> SeedBankAccountTypeTestData(IApplicationDbContext dbContext)
+ {
+ var testBankAccountTypes = AccountsSchema.GetBankAccountTypesSeedData();
+ dbContext.BankAccountTypes.AddRange(testBankAccountTypes);
+ await dbContext.SaveChangesAsync().ConfigureAwait(false);
+ return testBankAccountTypes.ToList();
+ }
+
+ private async Task> SeedCurrencyTestData(IApplicationDbContext dbContext)
+ {
+ var testCurrencies = CoreSchema.GetCurrencySeedData();
+ dbContext.Currencies.AddRange(testCurrencies);
+ await dbContext.SaveChangesAsync().ConfigureAwait(false);
+ return testCurrencies.ToList();
+ }
+
+ private async Task SeedUserProfileTestData(IApplicationDbContext dbContext, IDateTimeProvider dateTimeProvider)
+ {
var testUserProfile = new UserProfileEntity()
{
SignOn = "TestUser",
- Audit = GetAuditForCreate()
+ Audit = GetAuditForCreate(dateTimeProvider)
};
dbContext.UserProfiles.Add(testUserProfile);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
+ return testUserProfile;
+ }
- // TODO: Replace this with ICompanyRepository when it exists ...
+ private async Task SeedCompanyOwnerTestData(IApplicationDbContext dbContext, IDateTimeProvider dateTimeProvider, UserProfileEntity testUserProfile)
+ {
var testCompanyOwner = new OwnerEntity()
{
Company = new CompanyEntity()
@@ -109,41 +148,34 @@ protected async Task ResetDatabaseAsync()
CompanyNumber = "12345678910",
VATNumber = "zz1224324543",
DateOfIncorporation = DateTime.Today,
- Audit = GetAuditForCreate(),
+ Audit = GetAuditForCreate(dateTimeProvider),
UserProfile = testUserProfile
}
};
dbContext.Owners.Add(testCompanyOwner);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
+ return testCompanyOwner;
+ }
- // TODO: Replace this with IPersonalDetailsRepository when it exists ...
- var testPersonOwner = new OwnerEntity()
+ private async Task SeedPersonalOwnerTestData(IApplicationDbContext dbContext, IDateTimeProvider dateTimeProvider, UserProfileEntity testUserProfile)
+ {
+ var testPersonalOwner = new OwnerEntity()
{
PersonalDetails = new PersonalDetailsEntity()
{
- Audit = GetAuditForCreate(),
+ Audit = GetAuditForCreate(dateTimeProvider),
UserProfile = testUserProfile
}
};
- dbContext.Owners.Add(testPersonOwner);
+ dbContext.Owners.Add(testPersonalOwner);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
-
- AuditEntity GetAuditForCreate() => new() { CreatedBy = "TestUser", CreatedOn = dateTimeProvider.UtcNow };
+ return testPersonalOwner;
}
- protected virtual Action ConfigureTestServices() => services =>
- {
- // Register the WebAPIClient using the test httpClient ...
- services.AddTransient((sp) =>
- {
- Guard.Against.Null(_httpClient.BaseAddress, "httpClient.BaseAddress");
- return new AdminAssistantWebAPIClient(_httpClient) { BaseUrl = _httpClient.BaseAddress.ToString() };
- });
- services.AddAutoMapper(typeof(MappingProfile));
- };
-
+ private AuditEntity GetAuditForCreate(IDateTimeProvider dateTimeProvider)
+ => new() { CreatedBy = "TestUser", CreatedOn = dateTimeProvider.UtcNow };
-#region IDisposable
+ #region IDisposable
private bool disposedValue;