Skip to content

Commit

Permalink
#167 Updated IntegrationTestBase and DbContext SeedData code to allow…
Browse files Browse the repository at this point in the history
… the Respawn NuGet package to clear down Currency and BankAccount seed data and re-populate it when running tests.
  • Loading branch information
SimonGeering committed Apr 8, 2021
1 parent bfe71fb commit fe71997
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,33 @@

namespace AdminAssistant.Infra.DAL.EntityFramework.Model
{
internal class AccountsSchema
public static class AccountsSchema
{
private const string Name = "Accounts";

/// <summary>Sets up static lookup data for the accounts module.</summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="includeIDs">`True` for EF Core migration code otherwise `False`.</param>
/// <returns>Out of the box default bank account types.</returns>
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);
Expand Down Expand Up @@ -53,12 +76,8 @@ private static void BankAccountType_OnModelCreating(ModelBuilder builder)
builder.Entity<BankAccountTypeEntity>().Property(x => x.AllowCompany).IsRequired().HasDefaultValue(false);
builder.Entity<BankAccountTypeEntity>().Property(x => x.IsDeprecated).IsRequired().HasDefaultValue(false);

builder.Entity<BankAccountTypeEntity>().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<BankAccountTypeEntity>().HasData(GetBankAccountTypesSeedData(true));
}

private static void Payee_OnModelCreating(ModelBuilder builder)
{
Expand Down
33 changes: 26 additions & 7 deletions src/AdminAssistant.Infra/DAL/EntityFramework/Model/CoreSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,34 @@

namespace AdminAssistant.Infra.DAL.EntityFramework.Model.Core
{
internal class CoreSchema
public static class CoreSchema
{
private const string Name = "Core";

/// <summary>Sets up static lookup data for the core module.</summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="includeIDs">`True` for EF Core migration code otherwise `False`.</param>
/// <returns>Out of the box default currencies.</returns>
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);
Expand Down Expand Up @@ -76,12 +100,7 @@ private static void Currency_OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<CurrencyEntity>().Property(x => x.Symbol).IsRequired().IsUnicode().HasMaxLength(Currency.SymbolMaxLength).HasColumnType($"CHAR({Currency.SymbolMaxLength})");
modelBuilder.Entity<CurrencyEntity>().Property(x => x.DecimalFormat).IsRequired().HasMaxLength(Currency.DecimalFormatMaxLength).HasColumnType($"CHAR({Currency.DecimalFormatMaxLength})");
modelBuilder.Entity<CurrencyEntity>().Property(x => x.IsDeprecated).IsRequired().HasDefaultValue(false);
modelBuilder.Entity<CurrencyEntity>().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<CurrencyEntity>().HasData(GetCurrencySeedData(true));
}

private static void Owner_OnModelCreating(ModelBuilder modelBuilder)
Expand Down
82 changes: 57 additions & 25 deletions src/AdminAssistant.Test/IntegrationTestBase.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -69,9 +72,7 @@ public IntegrationTestBase()
{
"sysdiagrams",
"__EFMigrationsHistory",
"tblObjectType",
"Currency",
"BankAccountType"
"tblObjectType"
},
WithReseed = true
};
Expand All @@ -90,17 +91,55 @@ protected async Task ResetDatabaseAsync()
var dbContext = Container.GetRequiredService<IApplicationDbContext>();
var dateTimeProvider = Container.GetRequiredService<IDateTimeProvider>();

// 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<IServiceCollection> ConfigureTestServices() => services =>
{
// Register the WebAPIClient using the test httpClient ...
services.AddTransient<IAdminAssistantWebAPIClient>((sp) =>
{
Guard.Against.Null(_httpClient.BaseAddress, "httpClient.BaseAddress");
return new AdminAssistantWebAPIClient(_httpClient) { BaseUrl = _httpClient.BaseAddress.ToString() };
});
services.AddAutoMapper(typeof(MappingProfile));
};

private async Task<List<BankAccountTypeEntity>> SeedBankAccountTypeTestData(IApplicationDbContext dbContext)
{
var testBankAccountTypes = AccountsSchema.GetBankAccountTypesSeedData();
dbContext.BankAccountTypes.AddRange(testBankAccountTypes);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
return testBankAccountTypes.ToList();
}

private async Task<List<CurrencyEntity>> SeedCurrencyTestData(IApplicationDbContext dbContext)
{
var testCurrencies = CoreSchema.GetCurrencySeedData();
dbContext.Currencies.AddRange(testCurrencies);
await dbContext.SaveChangesAsync().ConfigureAwait(false);
return testCurrencies.ToList();
}

private async Task<UserProfileEntity> 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<OwnerEntity> SeedCompanyOwnerTestData(IApplicationDbContext dbContext, IDateTimeProvider dateTimeProvider, UserProfileEntity testUserProfile)
{
var testCompanyOwner = new OwnerEntity()
{
Company = new CompanyEntity()
Expand All @@ -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<OwnerEntity> 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<IServiceCollection> ConfigureTestServices() => services =>
{
// Register the WebAPIClient using the test httpClient ...
services.AddTransient<IAdminAssistantWebAPIClient>((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;

Expand Down

0 comments on commit fe71997

Please sign in to comment.