繁体   English   中英

如何在单元测试中验证 EF Core DBContext 配置

[英]How to validatie EF Core DBContext config in an unit test

当前,当 DBContext 模型的配置出现错误时,我们会在运行时收到错误消息。 例如:

实体类型“MyObject”需要定义一个主键。 如果您打算使用无键实体类型,请调用“HasNoKey()”。

首次在应用程序中使用 EF Core 时会抛出此错误。 我想在单元测试中验证模型。

我试过的

我注意到ModelValidator.Validate中的ModelValidator.Validate ,所以我尝试了这个:

[TestMethod]
public void MyDbContext_DoesNotThrowExceptions()
{
    // Arrange
    var myDbContext = CreateMyDbContext();
    IModel model = myDbContext.Model;

    var validator = new ModelValidator(new ModelValidatorDependencies(???,???)) // [EntityFrameworkInternal] public ModelValidatorDependencies([NotNull] ITypeMappingSource typeMappingSource,[NotNull] IMemberClassifier memberClassifier)

    // Act
    validator.Validate(model, ???); // public virtual void Validate(IModel model,IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
}

不幸的是,我现在不知道如何创建ModelValidator / ModelValidatorDependencies或作为IDiagnosticsLogger传递的IDiagnosticsLogger - 见??? 在代码中。 [EntityFrameworkInternal]让我觉得我有错误的方法。

任何人都知道如何修复此单元测试? (通过创建ModelValidator或通过其他方法)

细节

错误的完整堆栈跟踪:

Test method Foo threw exception: 
System.InvalidOperationException: The entity type 'MyEntity' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'.
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.Microsoft.EntityFrameworkCore.Internal.IDatabaseFacadeDependenciesAccessor.get_Dependencies()
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetFacadeDependencies(DatabaseFacade databaseFacade)
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(DatabaseFacade databaseFacade, String sql, IEnumerable`1 parameters)
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(DatabaseFacade databaseFacade, String sql, Object[] parameters)
   at myCode

解决方案

通过 soms 调整(EF Core 3 验证方法有 2 个参数),Vasil 的回答对我有用。 我现在有了:

[TestMethod]
public void MyDbContext_DoesNotThrowExceptions()
{
    // Arrange
    var serviceProvider = CreateServiceProvider();

    var validator = serviceProvider.GetService<IModelValidator>();
    var context = serviceProvider.GetService<MyDbContext>();
    var logger = serviceProvider.GetService<IDiagnosticsLogger<DbLoggerCategory.Model.Validation>>();

    // Act
    validator.Validate(context.Model, logger);
}

private static ServiceProvider CreateServiceProvider()
{
    var serviceCollection = new ServiceCollection()
        .AddEntityFrameworkSqlServer()
        .AddDbContext<MyDbContext>((sp, options) => options
            .UseSqlServer(new SqlConnection()));
    return serviceCollection.BuildServiceProvider();
}

我在 EFCore github 存储库中环顾四周,这是我设法开始工作的最好方法。

var serviceCollection = new Microsoft.Extensions.DependencyInjection.ServiceCollection();
serviceCollection.AddEntityFrameworkSqlServer().AddDbContext<Context>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var validator = serviceProvider.GetService<IModelValidator>();
var context = serviceProvider.GetService<Context>();

validator.Validate(context.Model); 

使用的所有类型都来自 ef 命名空间或来自 ef 所依赖的包,因此您应该能够毫无问题地运行它。

我已经用没有主键的单个实体对其进行了测试,它抛出异常“实体类型‘XXXXX’需要定义一个主键”,因此这应该与 ef 在执行第一个查询时所做的非常接近。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM