This is a post to store knowledge for future reference.
We have an ANZ application, and have segregated our application entities into its own DbContext - separate from ANZ. We do "share" some entities, however - for example - the AbpUsers table is included in our own DbContext - but we disable migrations for that table so it does not attempt to generate the table a second time.
We have started writing unit/integration tests for our business logic - and came across this problem - how do we mock the database, when we need BOTH the Abp tables, AND our own table schemas to be created into the mocked sqlite dbcontext? If we do nothing, we get an error when running the test, that tables could not be found.
The answer required 2 adjustments to achieve.
- Edit 'XXX.Test.Base/DependencyInjection/ServiceCollectionRegistrar.cs' to publish the sqlite in-memory connection to IoC
public static class ServiceCollectionRegistrar
{
public static void Register(IIocManager iocManager)
{
RegisterIdentity(iocManager);
var builder = new DbContextOptionsBuilder<AnzDbContext>();
var inMemorySqlite = new SqliteConnection("Data Source=:memory:");
builder.UseSqlite(inMemorySqlite);
// register connection for reuse
iocManager.IocContainer.Register(Component.For<SqliteConnection>().Instance(inMemorySqlite));
iocManager.IocContainer.Register(
Component
.For<DbContextOptions<AnzDbContext>>()
.Instance(builder.Options)
.LifestyleSingleton()
);
inMemorySqlite.Open();
new AnzDbContext(builder.Options).Database.EnsureCreated();
}
private static void RegisterIdentity(IIocManager iocManager)
{
var services = new ServiceCollection();
IdentityRegistrar.Register(services);
WindsorRegistrationHelper.CreateServiceProvider(iocManager.IocContainer, services);
}
}
- We derive our unit tests from the same unit test base as our Abp unit test classes - that triggers the Abp tables to be generated/mocked
- We edit our custom unit test "ServiceCollectionRegistrar" to locate the sqlite database connection from IoC, rather than initialize a new DB - however, we also need to use reflection to dig into EF to FORCE our custom table schema to be generated. Usually, the code will call
EnsureCreated
(new CustomDbContext(builder.Options).Database.EnsureCreated();
) - but reading the XmlDoc, you will see that if the DB already exists, it will do nothing - not even generate the schema - so we need to use reflection to access theCreate()
andCreateTables()
methods.
public static void Register(IIocManager iocManager)
{
RegisterIdentity(iocManager);
var builder = new DbContextOptionsBuilder<CustomDbContext>();
var inMemorySqlite = iocManager.Resolve<SqliteConnection>();
builder.UseSqlite(inMemorySqlite);
iocManager.IocContainer.Register(
Component
.For<DbContextOptions<CustomDbContext>>()
.Instance(builder.Options)
.LifestyleSingleton()
);
inMemorySqlite.Open();
var db = new CustomDbContext(builder.Options);
// FORCE the table schema to be created - even though the database already exists, it only contains ANZ tables - none of our own
var propDependencies = typeof(DatabaseFacade).GetProperty("Dependencies", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var dependencies = (IDatabaseFacadeDependencies)propDependencies.GetValue(db.Database);
if (dependencies.DatabaseCreator is IRelationalDatabaseCreator databaseCreator)
{
databaseCreator.Create();
databaseCreator.CreateTables();
}
}
2 Answer(s)
-
0
Hi @hra
I have asked to access your project for antoher problem. If you can share your project, we can check this problem as well.
-
0
Hi @ismcagdas - this isn't a question - I have posed a problem, and the solution in the one post - in case anybody else runs into this requirement. I probably should have clicked "close" when I posted it. Thanks - closing now.