Я реконструировал тестовую среду, поскольку она, похоже, предоставляется только тогда, когда вы создаете многоуровневое приложение. Я пытаюсь избежать этого (многоуровневой части), поскольку это простой проект, и мне не нужен такой уровень сложности.
У меня проблемы с запуском тестов, использующих мой собственный контекст БД.
Контекст не зарегистрирован, несмотря на то, что я это сделал:
private void ConfigureEfCore(ServiceConfigurationContext context)
{
// This should register the DbContext and the repositories
context.Services.AddAbpDbContext(options =>
{
/* create default repositories only for aggregate roots
* Documentation: https://docs.abp.io/en/abp/latest/Entit ... positories
*/
options.AddDefaultRepositories(includeAllEntities: true);
});
Configure(options =>
{
options.Configure(configurationContext => { configurationContext.UseSqlite(options => { }); });
});
}
Тем не менее, когда я запускаю тест, во время SeedTestData() он выдает:
.... ...
Autofac.Core.Registration.ComponentNotRegisteredException
The requested service 'WFT.CameraControl.Data.CameraControlDbContext' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Должен добавить, что само приложение работает нормально.
- Я проверил, что .AddAbpDbContext( ).
- В тестовой DLL (перечисленной ниже) есть только один AbpModule.
- Я настраиваю базу данных SQLLite после выполнения регистрация контекста БД в «обычном приложении». И в этом случае, поскольку код на самом деле не использует НАСТОЯЩИЙ модуль приложения, я явно настроил AbpDbContextOptions на UseSqlLite
Вот контекст моей базы данных:
using AppAny.Quartz.EntityFrameworkCore.Migrations;
using AppAny.Quartz.EntityFrameworkCore.Migrations.PostgreSQL;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using WFT.CameraControl.Entities;
namespace WFT.CameraControl.Data;
[ReplaceDbContext(typeof(IIdentityDbContext))]
[ReplaceDbContext(typeof(ITenantManagementDbContext))]
[ConnectionStringName("Default")]
public class CameraControlDbContext : AbpDbContext, ITenantManagementDbContext,
IIdentityDbContext
{
public const string DbTablePrefix = "App";
public const string DbSchema = null;
#region Entities from the modules
/* Notice: We only implemented IIdentityProDbContext and ISaasDbContext
* and replaced them for this DbContext. This allows you to perform JOIN
* queries for the entities of these modules over the repositories easily. You
* typically don't need that for other modules. But, if you need, you can
* implement the DbContext interface of the needed module and use ReplaceDbContext
* attribute just like IIdentityProDbContext and ISaasDbContext.
*
* More info: Replacing a DbContext of a module ensures that the related module
* uses this DbContext on runtime. Otherwise, it will use its own DbContext class.
*/
// Identity
public DbSet Users { get; set; }
public DbSet Roles { get; set; }
public DbSet ClaimTypes { get; set; }
public DbSet OrganizationUnits { get; set; }
public DbSet SecurityLogs { get; set; }
public DbSet LinkUsers { get; set; }
public DbSet UserDelegations { get; set; }
public DbSet Sessions { get; set; }
// Tenant Management
public DbSet Tenants { get; set; }
public DbSet TenantConnectionStrings { get; set; }
#endregion
// The sites, cameras and doors that are being monitored for this tenant
public DbSet Sites { get; set; }
public DbSet Cameras { get; set; }
public DbSet OpenableResources { get; set; }
public DbSet CameraSessions { get; set; }
public CameraControlDbContext(DbContextOptions options)
: base(options)
{
Console.Out.WriteLine("CameraControlDbContext created");
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureFeatureManagement();
builder.ConfigureIdentity();
builder.ConfigureOpenIddict();
builder.ConfigureTenantManagement();
builder.ConfigureBlobStoring();
// ConfigureQuartzTables(builder);
/* Configure your own entities here */
builder.Entity(b =>
{
b.ToTable("WFT_Sites", DbSchema);
b.ConfigureByConvention();
b.HasMany(s => s.Cameras).WithOne(c => c.Site);
b.HasMany(s => s.OpenableResources).WithOne(o => o.Site);
b.ApplyObjectExtensionMappings();
});
builder.Entity(b =>
{
b.ToTable("WFT_Cameras", DbSchema);
b.ConfigureByConvention();
b.HasMany(ca => ca.Actions)
.WithOne(a => a.Camera)
.HasForeignKey(ca => ca.Id);
b.HasIndex(c => c.CameraIdentifier).IsUnique();
b.ApplyObjectExtensionMappings();
});
builder.Entity(b =>
{
b.ToTable("WFT_CameraActions", DbSchema);
b.ConfigureByConvention();
b.HasOne().WithMany(c => c.Actions);
b.ApplyObjectExtensionMappings();
});
builder.Entity(b =>
{
b.ToTable("WFT_OpenableResources", DbSchema);
b.ConfigureByConvention();
b.HasIndex(r => r.ResourceIdentifier).IsUnique();
b.ApplyObjectExtensionMappings();
});
builder.Entity(b =>
{
b.ToTable("WFT_CameraSessions", DbSchema);
b.ConfigureByConvention();
// Map this so that we're a json column for this structure
b.OwnsOne(cs => cs.LprEvent, d =>
{
d.ToJson();
d.OwnsOne(evt => evt.Data);
});
b.ApplyObjectExtensionMappings();
});
}
private void ConfigureQuartzTables(ModelBuilder builder)
{
builder.AddQuartz(b => { b.UsePostgreSql(schema: DbSchema); });
}
}
```
---
And here is the entire test-module setup, for reference:
```
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Serilog;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Authorization;
using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.Caching;
using Volo.Abp.Data;
using Volo.Abp.Emailing;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Sqlite;
using Volo.Abp.FeatureManagement;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using Volo.Abp.PermissionManagement;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using Volo.Abp.Threading;
using Volo.Abp.Uow;
using WFT.CameraControl;
using WFT.CameraControl.Data;
namespace WFT.CameraControlTests.Base;
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpTestBaseModule),
typeof(AbpAuthorizationModule),
typeof(AbpBackgroundJobsAbstractionsModule),
// ABP Framework packages
typeof(AbpAutoMapperModule),
typeof(AbpCachingModule),
// Application
typeof(AbpAccountApplicationModule),
typeof(AbpAccountApplicationContractsModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpAccountApplicationModule),
typeof(AbpTenantManagementApplicationModule),
typeof(AbpSettingManagementApplicationModule),
// EFCore
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpBackgroundJobsEntityFrameworkCoreModule),
typeof(AbpAuditLoggingEntityFrameworkCoreModule),
typeof(AbpFeatureManagementEntityFrameworkCoreModule),
typeof(AbpIdentityEntityFrameworkCoreModule),
typeof(AbpOpenIddictEntityFrameworkCoreModule),
typeof(AbpTenantManagementEntityFrameworkCoreModule),
typeof(BlobStoringDatabaseEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqliteModule)
// For Background jobs, managed by Quartz
// Fails if you run more than one test at a time, as it tries to instantiate many singleton Quartz schedulers
// So for now, we'll just use the in-memory background job manager
// typeof(AbpBackgroundJobsQuartzModule),
)]
public class CameraControlTestBaseModule : AbpModule
{
/*
* We have to replicate much of what the main App Module does
* Because we can't depend on it in the test project (don't want all of it's HTTP imports)
*/
public override void PreConfigureServices(ServiceConfigurationContext context)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.Async(c => c.Console())
.CreateBootstrapLogger();
// https://www.npgsql.org/efcore/release-n ... ping-logic
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
PreConfigure(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("CameraControl");
options.UseLocalServer();
options.UseAspNetCore();
});
});
// PreConfigure(options => { options.IsBlazorWebApp = true; });
CameraControlGlobalFeatureConfigurator.Configure();
CameraControlModuleExtensionConfigurator.Configure();
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Turn off job execution...
Configure(options => { options.IsJobExecutionEnabled = false; });
context.Services.Replace(ServiceDescriptor.Singleton());
context.Services.AddAlwaysAllowAuthorization();
ConfigureMultiTenancy();
ConfigureAutoMapper(context);
ConfigureAutoApiControllers();
ConfigureEfCore(context);
// add in the assembly, which results in registering the services
// this is so that all the services and repositories are registered, so we can use them in the test
// var cameraControlAssembly = Assembly.GetAssembly(typeof(CameraControlAppService));
// if (cameraControlAssembly != null) context.Services.AddAssembly(cameraControlAssembly);
// EF Core
Configure(options =>
{
options.SaveStaticFeaturesToDatabase = false;
options.IsDynamicFeatureStoreEnabled = false;
});
Configure(options =>
{
options.SaveStaticPermissionsToDatabase = false;
options.IsDynamicPermissionStoreEnabled = false;
});
context.Services.AddAlwaysDisableUnitOfWorkTransaction();
ConfigureInMemorySqlite(context.Services);
}
private void ConfigureEfCore(ServiceConfigurationContext context)
{
// This should register the DbContext and the repositories
context.Services.AddAbpDbContext(options =>
{
/* create default repositories only for aggregate roots
* Documentation: https://docs.abp.io/en/abp/latest/Entit ... positories
*/
options.AddDefaultRepositories(includeAllEntities: true);
});
Configure(options =>
{
options.Configure(configurationContext => { configurationContext.UseSqlite(options => { }); });
});
}
private void ConfigureAutoApiControllers()
{
Configure(options =>
{
options.ConventionalControllers.Create(typeof(CameraControlModule).Assembly);
});
}
private void ConfigureMultiTenancy()
{
Configure(options => { options.IsEnabled = CameraControlModule.IsMultiTenant; });
}
private void ConfigureAutoMapper(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper();
Configure(options =>
{
/* Uncomment `validate: true` if you want to enable the Configuration Validation feature.
* See AutoMapper's documentation to learn what it is:
* https://docs.automapper.org/en/stable/C ... ation.html
*/
options.AddMaps( /* validate: true */);
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
SeedTestData(context);
}
private static void SeedTestData(ApplicationInitializationContext context)
{
AsyncHelper.RunSync(async () =>
{
using (var scope = context.ServiceProvider.CreateScope())
{
await scope.ServiceProvider
.GetRequiredService()
.SeedAsync();
}
});
}
// In memory SQLLite DB Stuff
public override void OnApplicationShutdown(ApplicationShutdownContext context)
{
_sqliteConnection?.Dispose();
}
private SqliteConnection? _sqliteConnection;
private void ConfigureInMemorySqlite(IServiceCollection services)
{
_sqliteConnection = CreateDatabaseAndGetConnection();
services.Configure(options =>
{
options.Configure(context => { context.DbContextOptions.UseSqlite(_sqliteConnection); });
});
}
private static SqliteConnection CreateDatabaseAndGetConnection()
{
var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();
var options = new DbContextOptionsBuilder()
.UseSqlite(connection)
.Options;
using (var context = new CameraControlDbContext(options))
{
context.GetService().CreateTables();
}
return connection;
}
}
```
Подробнее здесь: https://stackoverflow.com/questions/792 ... t-in-tests
Мобильная версия