jonpsmith / efcore.testsupport Goto Github PK
View Code? Open in Web Editor NEWTools for helping in unit testing applications that use Entity Framework Core
License: Other
Tools for helping in unit testing applications that use Entity Framework Core
License: Other
If you have a THP class in your model, then EfSchemaCompare will show an error on non-nullable properties in the non-base entities. That's because EF Core makes the columns nullable because those properties may not be used.
I'm not sure if I can catch that and stop these errors, but its worth having a look. Not urgent, but nice to have.
A small suggestion for this handy little feature.
if (log.EventId.Name != RelationalEventId.CommandError.Name && log.EventId.Name != RelationalEventId.CommandExecuted.Name)
My use case was encountering a foreign key constraint error from sqlite when constructing a test database to run a unit test against - of course sqlite being unable to tell me which constraint I was violating. With a copy of the class with that small change I was able to pull the sql being executed and find what I was doing wrong. Maybe helpful in other situations too?
Can the readme and wiki be updated to have obvious upfront statements about supported databases somewhere?
I completely failed to check supported providers. I was totally excited to use this until I got the lovely "This is not a database provider that we currently support." ::SAD_FACE::
Is the level of effort required to support other providers such as Postgres too steep?
Tested using EfCore.TestSupport nuget package 3.1.0
Consider a table
CREATE TABLE [dbo].[Foos]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[IsFoosable] [bit] NOT NULL DEFAULT 1,
CONSTRAINT [PK_Foos] PRIMARY KEY CLUSTERED (Id)
)
Consider an entity
public class Foo
{
[Key]
public int Id { get; set; }
public bool IsFoosable { get; set; }
}
Consider a context
public class FooContext : DbContext
{
public DbSet<Foo> Foos { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Foo>()
.Property(x => x.IsFoosable)
.HasDefaultValue(true);
}
}
Then the test
//--------- Arrange ---------//
string connectionString = ...;
var config = new CompareEfSqlConfig();
var comparer = new CompareEfSql(config);
using (var fooContext = CreateFooContext())
{
//--------- Act ---------//
var hasErrors = comparer.CompareEfWithDb(connectionString, fooContext);
//--------- Assert ---------//
Assert.False(hasErrors, comparer.GetAllErrors);
}
Will fail with:
Message:
DIFFERENT: Foo->Property 'IsFoosable', default value sql. Expected = True, found = 1
If the context instead does:
...
modelBuilder.Entity<Foo>()
.Property(x => x.IsFoosable)
.HasDefaultValue(1);
...
The failure is still
Message:
DIFFERENT: Foo->Property 'IsFoosable', default value sql. Expected = True, found = 1
So there appears to be no way to configure a default value for boolean
/ bit not null
that EfCore.TestSupport will consider to be comparable.
CompareEfWithDb method throws the following exception on EF Core 5 Preview 7:
System.InvalidOperationException : Unable to resolve service for type 'Microsoft.EntityFrameworkCore.Diagnostics.IDbContextLogger' while attempting to activate 'Microsoft.EntityFrameworkCore.Internal.DiagnosticsLogger`1[Microsoft.EntityFrameworkCore.DbLoggerCategory+Scaffolding]'.
Exception doesn't have a stacktrace
I know that TablesToIgnoreCommaDelimited already exists, but I could not undertand how I had to use it properly. My contexts contains only a small amount of table. Should I have enumerate all tables from the DB, that do not exist in the context?
So It would be greate to have such option to declare only required tables.
I've impemented the following solution:
Added new config properties:
public bool CompareOnlyExistingTables { get; set; }
internal string TablesToCompareCommaDelimited { get; set; }
Updated 2 methods:
private DatabaseModel GetDatabaseModelViaScaffolder(DbContext context, string configOrConnectionString, IDesignTimeServices designTimeService)
{
var serviceProvider = designTimeService.GetDesignTimeProvider();
var factory = serviceProvider.GetService<IDatabaseModelFactory>();
var connectionString = configOrConnectionString == null
? context.Database.GetDbConnection().ConnectionString
: GetConfigurationOrActualString(configOrConnectionString);
//FIXED
_config.TablesToCompareCommaDelimited = _config.CompareOnlyExistingTables ? string.Join(",", context.Model.GetEntityTypes()
.Select(r => string.IsNullOrEmpty(r.Relational().Schema) ? r.Relational().TableName : $"{r.Relational().Schema}.{r.Relational().TableName}")) : string.Empty;
var databaseModel = factory.Create(connectionString, new string[] { }, new string[] { });
RemoveAnyTabletoIgnore(databaseModel);
return databaseModel;
}
private void RemoveAnyTabletoIgnore(DatabaseModel databaseModel)
{
//FIXED
List<DatabaseTable> CreateTableList(string list)
{
var tableList = new List<DatabaseTable>();
foreach (var tableToIgnore in list.Split(',')
.Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)))
{
var split = tableToIgnore.Split('.').Select(x => x.Trim()).ToArray();
var schema = split.Length == 1 ? databaseModel.DefaultSchema : split[0];
var tableName = split.Length == 1 ? split[0] : split[1];
var tableToRemove = databaseModel.Tables
.SingleOrDefault(x => x.Schema.Equals(schema, StringComparison.InvariantCultureIgnoreCase)
&& x.Name.Equals(tableName, StringComparison.InvariantCultureIgnoreCase));
if (tableToRemove == null)
throw new InvalidOperationException(
$"The TablesToIgnoreCommaDelimited config property contains a table name of '{tableToIgnore}', which was not found in the database");
tableList.Add(tableToRemove);
}
return tableList;
}
if (_config.TablesToIgnoreCommaDelimited != null)
{
foreach (var tableToRemove in CreateTableList(_config.TablesToIgnoreCommaDelimited))
{
databaseModel.Tables.Remove(tableToRemove);
}
}
if (!string.IsNullOrEmpty(_config.TablesToCompareCommaDelimited))
{
var tablesToRemove = databaseModel.Tables.Where(r => !CreateTableList(_config.TablesToCompareCommaDelimited).Contains(r)).ToList();
foreach (var tableToRemove in tablesToRemove)
{
databaseModel.Tables.Remove(tableToRemove);
}
}
}
When primary key is not defined in SQL DB, many null exceptions are thrown instead of logging the error.
I got this error in a call to CompareEfWithDb:
DIFFERENT: CommandGroup->Property 'CreateDate', default value sql. Expected = , found = '0001-01-01T00:00:00.0000000'\nDIFFERENT: CommandGroup->Property 'CreateDate', value generated. Expected = Never, found = OnAdd
I may not configure it correctly, but this CreateDate field is a standard DateTime field, with default configuration of EF Core 2.2:
public DateTime CreateDate { get; set; }
In SQL Server:
[CreateDate] datetime2 NOT NULL
EF Core 3.1 works on .NET Standard 2.0 (i.e. you can use it along with the .NET Framework).
The library doesn't with .NET Framework 4.7.2 and EF Core 3.1, because the project references EF Core 2.0 for .NET Standard 2.0, although it can use 3.0.
Migration from .NET Framework to .NET Core 5.0 is going to be a long one and it would be good to support framework for some time.
When I tried it, it failed because of different factory methods in 2.0 and 3.1
Hi,
Firstly thank you very much for this useful lib, it'll help us a lot.
I'm facing an issue when calling creating seed data with Assembly.GetCallingAssembly()).Location
, when referencing the project from NuGet.org the Assembly.GetCallingAssembly()).Location
points to C:\Users\username\.nuget\packages\efcore.testsupport\2.0.0\lib\netstandard2.0\TestSupport.dll
and TestSupport was unable to find \bin\
part in it and threw an exception.
Everything works fine when I reference directly your project in my solution.
The issue is present with built-in Visual Studio's test runner and with dotnet test
, didn't tested with others.
A seed JSON file is created in current test's folder
An exception is thrown.
System.Exception: Did not find '\bin' in the assembly. Do you need to provide the callingAssembly parameter?
Stack Trace:
at TestSupport.Helpers.TestData.GetCallingAssemblyTopLevelDir(Assembly callingAssembly)
at TestSupport.Helpers.TestData.GetTestDataDir(String alternateTestDir, Assembly callingAssembly)
at TestSupport.SeedDatabase.SeedJsonHelpers.FormJsonFilePath(String fileSuffix)
at TestSupport.SeedDatabase.SeedJsonHelpers.WriteJsonToJsonFile(String fileSuffix, String json)
at Trianon.HR.Data.EFCore.Tests.FilterTests.ExampleExtract() in C:\ieu\development\HR.Data\tests\Trianon.HR.Data.EFCore.Tests\FilterTests.cs:line 29
I saw that issues #4 and #14 face the same issue that should have been fixed since then but it seems it's still here...
I'll send you a PR to try to provide a way to avoid this issue in the future.
Hi Jon,
This is probably more of a feature request than issue but is there a way to get the CompareEFWithDB Method to check for Views as well as tables. EF Core doesn't actually care which you use and it can be especially useful when wanting to get data from other databases or linked servers, where a table would not be appropriate.
It would also need the issue with missing Primary Keys to be solved however (issue #32 ) as obviously the view does not have a Primary Key associated with it.
Worth noting that you can work around this by both including the View in TablesToIgnoreCommaDelimited and then subsequently also adding the error string "NOT IN DATABASE: Entity 'XXXXX', table name. Expected = XXXXView" but it's a bit messy!
Any help would be greatly appreciated as have been really loving this library so far :)
Many thanks,
Louis
I've been trying to use the CreateUniqueClassOptions method to set up a SQL Server xUnit test via your Nuget package. I cannot get it to work properly. I believe I have discovered that the cause is the use of use of
var pathToManipulate = (callingAssembly ?? Assembly.GetCallingAssembly()).Location;
in the GetCallingAssemblyTopLevelDir method. It appears that the result of this is not as expected, since the assembly being referenced is the Nuget package, which does not have the "bin" directory that you reference. As such, it causes a problem with your indexOfPart var returning zero.
Also, I think your logic here might be wonky:
var indexOfPart = pathToManipulate.IndexOf(binDir, StringComparison.OrdinalIgnoreCase) + 1; if (indexOfPart < 0) throw new Exception($"Did not find '{binDir}' in the ApplicationBasePath");
If the value for "bin" is not found, then your IndexOf will be -1. You then add 1 to that, which would result in zero. You then check to see if the result is LESS than zero. You need to check if it equals zero. Right now, it blows up in the Substring function with a length of -1.
Thank you for this library!
Wanted to bring to your notice that due to the inclusion of System.Net.Http v4.3.0 in your library, it is being flagged as a security risk due to this CVE - dotnet/announcements#88. Hopefully, you will be able to resolve this soon.
Hi,
We're finishing up a migration from EF6 to EF Core, and using CompareEfSql to validate the upgraded builder (especially the corner cases), and it's been a great tool to assist with this.
However we're having a small issue where the real schema was initially created all lowercase version, but the schema has since been changed to be pascal case. Further, either EF6 pascal cased the foreign key names, or perhaps another developer manually ignored the change when the schema was changed to pascal case.
The result is a mix of schema.Table
and FK_Schema_ColumnId
that is perfectly legal for Sql Server, and EF Core. The updated configuration works without errors.
public void Configure(EntityTypeBuilder<Terminal> builder)
{
builder.ToTable(table: "Terminal", schema: "Store");
I realize we can just ignore these errors individually, but as with #9 it would be great to add a case-insensitive option when comparing schema (and/or table).
NOT IN DATABASE: Entity 'Terminal', table name. Expected = Store.Terminal
but once ignored, we then get the reverse error
EXTRA IN DATABASE: YourDatabaseName->Table 'store.Terminal'`
We would like it if the following does not fail
CREATE TABLE [purchase].[Order] ....
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.ToTable(table: "Order", schema: "Purchase"); // originally purchase
}
[Test]
public void ShouldMatchSchema()
{
using (var context = new MyDbContext())
{
var config = new CompareEfSqlConfig();
config.SchemaIgnoreCase = true;
var comparer = new CompareEfSql(config);
//ATTEMPT
//This will compare EF Core model of the database
//with the database that the context's connection points to
var hasErrors = comparer.CompareEfWithDb(context);
//VERIFY
//The CompareEfWithDb method returns true if there were errors.
//The comparer.GetAllErrors property returns a string
//where each error is on a separate line
Assert.That(hasErrors, Is.False, comparer.GetAllErrors);
}
}
Thanks again for the great tool!
Hello,
we are using the CreateUniqueMethodOptions for testing. Now we added a temporal table and we are getting following error while executing the tests:
Microsoft.Data.SqlClient.SqlException: Failed to delete the XXX table because this is not a supported operation for temporal tables with system versioning.
If I delete the table on my own, the test works fine once. But then, I will get the error again...
Does this method supports temporal tables und if yes, how?
Thanks,
Jenny
Entity:
public class NormativeReference
{
[Key, MaxLength (50)]
public string NormativeReferenceId { get; set; }
public string Name { get; set; }
}
SQL (SQL Server 2014):
CREATE TABLE [dbo].[NormativeReferences] (
[NormativeReferenceId] NVARCHAR (50) NOT NULL,
[Name] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_NormativeReferences] PRIMARY KEY CLUSTERED ([NormativeReferenceId] ASC)
);
CompareEfWithDb returns:
DIFFERENT: NormativeReference->Property 'NormativeReferenceId', value generated. Expected = OnAdd, found = Never
Inside various pipeline based software, it is necessary to allow configuration to be overridable by Environmental Variables. as a means to help match up services. Inside AppSettings.GetConfiguration, would it be possible to add environment variables such that "ASPNETCORE_ConnectionStrings__PostgreSqlConnection" can override the connection string?
Does SQLite in-memory by default re-use DbContext instances?
I'm not sure if this is a more general SQLite issue or related specifically to EfCore.TestSupport.
Here's my general test setup...
public class MyDbFixture
{
public MyDbFixture()
{
// A custom `IDateTimeAdapter` to make testing easier with .NET DateTime
var now = DateTime.UtcNow;
TestDateTime = new Mock<IDateTimeAdapter>();
TestDateTime
.SetupGet(dt => dt.UtcNow)
.Returns(now);
}
// All db tests will use this method to create the DbContext
// The same mocked instance of `IDateTimeAdapter` is passed in, used for setting default values for date columns
public MyDbContext CreateDbContext()
{
var options = SqliteInMemory.CreateOptions<MyDbContext>();
var context = new MyDbContext(options, TestDateTime);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
return context;
}
}
Running the following tests presents no problem....
public class MyTests1
{
public MyTestsA(MyDbFixture fixture)
{
_fixture = fixture;
}
public async Task MyTest1()
{
using var dbContext = _fixture.CreateDbContext()
.... do testing stuff
}
public async Task MyTest2()
{
using var dbContext = _fixture.CreateDbContext()
.... do testing stuff
}
}
However, adding this test will cause the previous tests to occasionally fail when all tests are run together
public class MyTestsB
{
public async Task MyOtherTest()
{
var options = SqliteInMemory.CreateOptions<MyDbContext>();
// No Mock Setup for IDateTimeAdapter
using var context = new OrderPollingDbContext(options, new Mock<IDateTimeAdapter>().Object);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
.... do testing stuff
}
}
I notice the following:
MyTestsA
will have a MyDbContext
IDateTimeAdapter.UtcNow
of DateTime.MinValue
. This is unexpected.MyTestsB
, MyTestsA
stop failing.MyTestsA
only continue to pass, even if DbContext is reused, because each test is using the same Mock<IDateTimeAdapter>
Hey Jon,
I'm getting the following exception from a call to CreateUniqueClassOptions
:
'Did not find '\bin\' in the assembly. Do you need to provide the callingAssembly parameter?'
Stack:
TestSupport.dll!TestSupport.Helpers.TestData.GetCallingAssemblyTopLevelDir(System.Reflection.Assembly callingAssembly)
TestSupport.dll!TestSupport.Helpers.AppSettings.GetConfiguration(System.Reflection.Assembly callingAssembly, string settingsFilename)
TestSupport.dll!TestSupport.Helpers.AppSettings.GetUniqueDatabaseConnectionString(object testClass, string optionalMethodName, char seperator)
TestSupport.dll!TestSupport.EfHelpers.SqlServerHelpers.CreateOptionWithDatabaseName<Entities.ProprietaryContext>(object callingClass, bool throwOnClientServerWarning, string callingMember)
TestSupport.dll!TestSupport.EfHelpers.SqlServerHelpers.CreateUniqueClassOptions<Entities.ProprietaryContext>(object callingClass, bool throwOnClientServerWarning)
Calling code:
[Fact]
public void NoCompany()
{
var options = this.CreateUniqueClassOptions<ProprietaryContext>();
...
I see the exception on Helpers/TestData.cs:158, but am not getting anywhere without symbols.
Any thoughts?
Thanks!
The problem is I need to add to the dbcontextoptionsbuilder the net topology options but currently I can't because all methods don't have the proper lambda like the constructor while using the adddbcontext option
Tested using EfCore.TestSupport nuget package 3.1.0
If entity framework is configured to have a Sql default that is the same as the C# default(T), then comparison incorrectly fails with an error similar to:
DIFFERENT: FooEntity->Property 'MyNumberWithDefault', default value sql. Expected = 0, found = <null>
DIFFERENT: FooEntity->Property 'MyNumberWithDefault', value generated. Expected = OnAdd, found = Never
Duplication:
public class FooTest
{
public class FooEntity
{
[Key]
public int Id { get; set; }
public int MyNumberWithDefault { get; set; }
}
public class FooContext : DbContext
{
public FooContext(DbContextOptions dbContextOptions) : base(dbContextOptions) { }
public DbSet<FooEntity> FooEntity { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<FooEntity>()
.Property(x => x.MyNumberWithDefault)
//NOTE: Change this to any other value besides 0, and the test passes
.HasDefaultValue(0);
}
}
[Fact]
public async Task ShouldAllowDefaultDefaultValue()
{
//----- Arrange -----//
var dbContextOptions = new DbContextOptionsBuilder<FooContext>().UseSqlServer(this.GetUniqueDatabaseConnectionString());
using (var fooContext = new FooContext(dbContextOptions.Options))
{
await fooContext.Database.EnsureDeletedAsync();
await fooContext.Database.EnsureCreatedAsync();
}
//----- Act -----//
var config = new CompareEfSqlConfig();
var comparer = new CompareEfSql(config);
var hasErrors = comparer.CompareEfWithDb(new FooContext(dbContextOptions.Options));
//----- Act -----//
Assert.False(hasErrors, comparer.GetAllErrors);
}
}
After upgrading my solution and test project to .NET Core 3.0, I get this error
System.MissingMethodException : Method not found: 'Microsoft.EntityFrameworkCore.Scaffolding.Metadata.DatabaseModel Microsoft.EntityFrameworkCore.Scaffolding.IDatabaseModelFactory.Create(System.String, System.Collections.Generic.IEnumerable
1<System.String>, System.Collections.Generic.IEnumerable
1<System.String>)'.
at TestSupport.EfSchemeCompare.CompareEfSql.GetDatabaseModelViaScaffolder(DbContext[] contexts, String configOrConnectionString, IDesignTimeServices designTimeService)
at TestSupport.EfSchemeCompare.CompareEfSql.FinishRestOfCompare(String configOrConnectionString, DbContext[] dbContexts, IDesignTimeServices designTimeService)
at TestSupport.EfSchemeCompare.CompareEfSql.CompareEfWithDb(String configOrConnectionString, DbContext[] dbContexts)
at TestSupport.EfSchemeCompare.CompareEfSql.CompareEfWithDb(DbContext[] dbContexts)
Is there a plan on updating the project to .NET Core 3?
As SQL Server is in most cases case insensitive for its structure, it may be a good idea to make the checks case insensitive by default?
Currently a property named Metadata
will not match a column named MetaData
, and the script will returns that the column is missing.
DIFFERENT: Message->Property 'MessageContent', default value sql. Expected = , found = N''
Basically any property on an entity which is configured with some variation of .IsRequired().HasDefaultValue("") is giving this error.
Using .IsRequired().HasDefaultValue("").HasDefaultValueSql("N''") does not result in any error, but I don't think that should be necessary?
I believe that there shouldn't be any reported errors if EF Core is in full control of the database structure, but I could just be misunderstanding what the expected behavior is.
Using Sql Server
Latest version of Entity Framework packages (2.2.3)
Latest EfCore.TestSupport (1.8.0)
Context:
public class EfTestContext : DbContext
{
public EfTestContext(DbContextOptions<EfTestContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Message>()
.ToTable("Message")
.Property(b => b.MessageContent).IsRequired().HasDefaultValue("");
}
public DbSet<Message> Messages { get; set; }
}
public class Message
{
public int MessageId { get; set; }
public string MessageContent { get; set; }
}
Unit Test:
[Fact]
public void EfTestSchemaCompare()
{
//SETUP
DbContextOptionsBuilder<EfTestContext> builder = new DbContextOptionsBuilder<EfTestContext>();
builder.UseSqlServer("Server=.\\SQLEXPRESS;Database=EfTest;Integrated Security=true;");
using (EfTestContext context = new EfTestContext(builder.Options))
{
CompareEfSql comparer = new CompareEfSql();
//ATTEMPT
//This will compare EF Core model of the database with the database that the context's connection points to
bool hasErrors = comparer.CompareEfWithDb(context);
//VERIFY
//The CompareEfWithDb method returns true if there were errors.
//The comparer.GetAllErrors property returns a string, with each error on a separate line
hasErrors.ShouldBeFalse(comparer.GetAllErrors);
}
}
Sql:
IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL
BEGIN
CREATE TABLE [__EFMigrationsHistory] (
[MigrationId] nvarchar(150) NOT NULL,
[ProductVersion] nvarchar(32) NOT NULL,
CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
);
END;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20190407183740_initial')
BEGIN
CREATE TABLE [Message] (
[MessageId] int NOT NULL IDENTITY,
[MessageContent] nvarchar(max) NOT NULL DEFAULT N'',
CONSTRAINT [PK_Message] PRIMARY KEY ([MessageId])
);
END;
GO
IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20190407183740_initial')
BEGIN
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20190407183740_initial', N'2.2.3-servicing-35854');
END;
GO
Hi Jon, I very like your tool, but I faced with some issue during using it.
Firstly, exception occurs when checking tables without PK (null reference exception).
Unfortunatelly, I have not saved a log. But I've made a quick fix by using null propagation, for example:
public bool CompareModelToDatabase(DatabaseModel databaseModel)
{
//.....
logger.CheckDifferent(entityType.FindPrimaryKey().Relational().Name, databaseTable.PrimaryKey**?**.Name,
CompareAttributes.ConstraintName);
//.....
}
And
private void CompareColumns(CompareLog log, IEntityType entityType, DatabaseTable table)
{
var columnDict = table.Columns.ToDictionary(x => x.Name);
var primaryKeyDict = table.PrimaryKey == null ? new Dictionary<string, DatabaseColumn>() : table.PrimaryKey.Columns.ToDictionary(x => x.Name);
//....
pKeyLogger.CheckDifferent(efPKeyConstraintName, table.PrimaryKey?.Name, CompareAttributes.ConstraintName);
This is just a quick fix, because the absence of PK is identified as “DIFFERENCE”.
Thanks.
Currently tests are failing becouse seems that library tries to call internal EF Core method that are not available now. Do you plan to update the library?
For our integration tests, we created a DbContext like this:
DbContextOptions<TestDbContext>? options = this.CreateUniqueMethodOptions<TestDbContext>();
await using TestDbContext dbContext = new(options);
How is it possible to use the connection string from the secrets.json?
I am getting this error:
System.PlatformNotSupportedException : LocalDB is not supported on this platform.
from the CreateEmptyViaWipe method on my Linux development machine, or simply by using context.Database.EnsureCreated(). Is this a setting that can be changed in CreateUniqueClassOptions?
Hello there,
Just a heads up. I updated to use EF Core 8.0 and the tests which rely on this TestSupport library fail with the MissingMethodException
:
Exception has occurred: CLR/System.MissingMethodException
Exception thrown: 'System.MissingMethodException' in Microsoft.EntityFrameworkCore.Relational.dll: 'Method not found: 'Microsoft.EntityFrameworkCore.Storage.RelationalTypeMapping Microsoft.EntityFrameworkCore.Storage.RelationalTypeMapping.Clone(System.String, System.Nullable`1<Int32>)'.'
at Microsoft.EntityFrameworkCore.Sqlite.Storage.Internal.SqliteTypeMappingSource.FindMapping(RelationalTypeMappingInfo& mappingInfo)
at Microsoft.EntityFrameworkCore.Storage.RelationalTypeMappingSource.<>c.<FindMappingWithConversion>b__8_0(ValueTuple`4 k, RelationalTypeMappingSource self)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd[TArg](TKey key, Func`3 valueFactory, TArg factoryArgument)
at Microsoft.EntityFrameworkCore.Storage.RelationalTypeMappingSource.FindMappingWithConversion(RelationalTypeMappingInfo mappingInfo, Type providerClrType, ValueConverter customConverter)
at Microsoft.EntityFrameworkCore.Storage.RelationalTypeMappingSource.FindMapping(Type type, IModel model, CoreTypeMapping elementMapping)
at Microsoft.EntityFrameworkCore.Metadata.Internal.MemberClassifier.IsCandidateNavigationPropertyType(Type targetType, MemberInfo memberInfo, Model model, Nullable`1& shouldBeOwned)
at Microsoft.EntityFrameworkCore.Metadata.Internal.MemberClassifier.FindCandidateNavigationPropertyType(MemberInfo memberInfo, IConventionModel model, Nullable`1& shouldBeOwned)
at Microsoft.EntityFrameworkCore.Metadata.Internal.MemberClassifier.GetNavigationCandidates(IConventionEntityType entityType)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ForeignKeyAttributeConvention.ProcessEntityTypeAdded(IConventionEntityTypeBuilder entityTypeBuilder, IConventionContext`1 context)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnEntityTypeAdded(IConventionEntityTypeBuilder entityTypeBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnEntityTypeAddedNode.Run(ConventionDispatcher dispatcher)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.DelayedConventionScope.Run(ConventionDispatcher dispatcher)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run()
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Dispose()
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelInitialized(IConventionModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelInitialized(IConventionModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Model..ctor(ConventionSet conventions, ModelDependencies modelDependencies, ModelConfiguration modelConfiguration)
at Microsoft.EntityFrameworkCore.ModelBuilder..ctor(ConventionSet conventions, ModelDependencies modelDependencies, ModelConfiguration modelConfiguration)
at Microsoft.EntityFrameworkCore.ModelConfigurationBuilder.CreateModelBuilder(ModelDependencies modelDependencies)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p)
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 callSite, 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 callSite, 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 callSite, 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 callSite, 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 callSite, 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 callSite, 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__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, 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_ContextServices()
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(IInfrastructure`1 accessor, Type serviceType)
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.EnsureCreated()
at Birder.Tests.Controller.PostFollowUserAsyncTests.<PostFollowUserAsync_ReturnsOkObject_WhenRequestIsValid>d__7.MoveNext() in C:\Users\user\source\repos\birder-server\Birder.Tests\Controller\NetworkController\PostFollowUserAsyncTests.cs:line 185
If I revert the EF Core packages back to version 7.0.14 (keeping the target framework net8) then the tests PASS again.
For example:
<TargetFramework>net8.0</TargetFramework>
...
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.14">
Think it's just a case of adding the new dependencies to EfCore.TestSupport .csproj.
Please let me know if you need any further information.
(and thank you for the library which is excellent :) )
Hi,
I am using nuget EfCore.TestSupport
with latest 3.1.0 version.
I get unhandled exception thrown when constructing new CompareEfSql()
.
I run similar test to test CompareViaContext
in ComparerBooks
class.
If I run it on windows it completes without error but on linux (ubuntu 18.04) it throws following error:
System.TypeInitializationException : The type initializer for 'TestSupport.EfSchemeCompare.Internal.CompareHelpers' threw an exception.
---- System.ArgumentException : An item with the same key has already been added. Key: System.CultureAwareComparer
Full stack trace:
at TestSupport.EfSchemeCompare.Internal.CompareHelpers.GetStringComparison(StringComparer caseComparer) in /builds/web/notifications/notifications-api/TestSupport/EfSchemeCompare/Internal/CompareHelpers.cs:line 43
at TestSupport.EfSchemeCompare.Internal.Stage1Comparer..ctor(IModel model, String dbContextName, CompareEfSqlConfig config, List`1 logs) in /builds/web/notifications/notifications-api/TestSupport/EfSchemeCompare/Internal/Stage1Comparer.cs:line 36
at TestSupport.EfSchemeCompare.CompareEfSql.FinishRestOfCompare(String configOrConnectionString, DbContext[] dbContexts, IDesignTimeServices designTimeService) in /builds/web/notifications/notifications-api/TestSupport/EfSchemeCompare/CompareEfSql.cs:line 131
at TestSupport.EfSchemeCompare.CompareEfSql.CompareEfWithDb(String configOrConnectionString, DbContext[] dbContexts) in /builds/web/notifications/notifications-api/TestSupport/EfSchemeCompare/CompareEfSql.cs:line 97
at TestSupport.EfSchemeCompare.CompareEfSql.CompareEfWithDb(DbContext[] dbContexts) in /builds/web/notifications/notifications-api/TestSupport/EfSchemeCompare/CompareEfSql.cs:line 63
at Notifications.DatabaseSchemaTests.DatabaseSchemaTests.CompareViaContext() in /builds/web/notifications/notifications-api/test/Notifications.DatabaseSchemaTests/DatabaseSchemaTests.cs:line 29
----- Inner Stack Trace -----
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at TestSupport.EfSchemeCompare.Internal.CompareHelpers..cctor() in /builds/web/notifications/notifications-api/TestSupport/EfSchemeCompare/Internal/CompareHelpers.cs:line 46
It seems that some keys in dictionary ComparerToComparison are equal to each other which is strange.
GetUniqueDatabaseConnectionString
doesn't always return a unique result.
For example, if I need to create two databases in a single test, then the default behavior won't generate two distinct connection strings. This is easily worked around by adding extra "jitter" to the test name in addition to e,g, $"{nameof(MyTestMethod)}_1"
and $"{nameof(MyTestMethod)}_2"
A bit more significant concern is that if for some reason a test database fails to get cleaned up at the end of execution, GetUniqueDatabaseConnectionString
will return the same connection string the next test run, possibly causing the test to fail in exciting and exotic ways.
This can also be worked around by adding extra code to check for the existence of the database before executing the rest of the test - but that is extra code to write, or by adding uniqueness "jitter" to the testName, e.g. this.GetUniqueDatabaseConnectionString($"{nameof(MyTestMethod)}_{Guid.NewGuid()}");
However, it caught me by surprise the first time that happened, and I wonder if the utility should provide out-of-the-box support for generating truly unique database names, or perhaps ensuring that the database doesn't already exist before returning the "unique" connection string?
Or perhaps just update the documentation at https://github.com/JonPSmith/EfCore.TestSupport/wiki/3b.-Creating-connection-strings#the-getuniquedatabaseconnectionstring-extention-method to more clearly indicate that a test database left over from a previous run may cause issues?
Hello,
please insert Support for DBQuery in ComporeEfSql / CompareEfWithDb.
Thanks.
Carsten
When using update to save the entity the test will fail. If you just change properties and save everuthing works fine.
The erros says: Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException : Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
On my setup, Rider 2019.1.2. on Windows 10 1809, the GetAllErrors() method can cause multiline test assertions to fail because they are expecting lines to be separated by '\r\n' rather than by '\n'.
I can get them to pass by replacing the '\n' separator in the string.Join() method with Environment.NewLine.
We should add this project to the EF Core Tools & Extensions page.
Running this against our database we are getting an exception when running
var hasErrors = comparer.CompareEfWithDb(context);
Exception:
System.ArgumentException: An item with the same key has already been added. Key: Job
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at System.Linq.Enumerable.ToDictionary[TSource,TKey](List`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
at TestSupport.EfSchemeCompare.Internal.Stage1Comparer.CompareModelToDatabase(DatabaseModel databaseModel)
at TestSupport.EfSchemeCompare.CompareEfSql.FinishRestOfCompare(String configOrConnectionString, DbContext[] dbContexts, IDesignTimeServices designTimeService)
at Gravity.EF.Test.DummyTestFixture.CompareViaContext()
After checking our database turns out we have two tables:
HangFire.Job (external table)
replication.Job (another external table)
Is there any way of ignoring some schemas? or specifying the default EF schema?
Any suggestion on handling these are much appreciated.
Thanks for this amazing lib.
Hi,
I ran into minor bug with nuget EfCore.TestSupport 3.1.1 version (latest).
I get unhandled NullReferenceException
thrown in Stage1Comparer.CompareModelToDatabase(DatabaseModel databaseModel) line 297
.
The problem occurs when a primary key is missing in a SQL table but is present in EF Core model.
repro:
CREATE TABLE [MyEntities] (
[MyEntityId] int NOT NULL
);
public class MyEntity
{
public int MyEntityId { get; set; }
}
...
public DbSet<MyEntity> MyEntities { get; set; }
I would expect a warning message explaining missing primary key in a SQL table
I found out that there is similar issue #8 but is closed. The issue was fixed with check for primary key in EF Core model. IMO similar check should be for SQL model.
In .Net 4.7.1 you need to call the SQLitePCL.Batteries.Init() on the test initializer. In net core it works as expected.
After installing EfCore.TestSupport I started getting build warnings regarding System.IO.Pipelines:
Microsoft.Common.CurrentVersion.targets(2389,5): Warning MSB3277 : Found conflicts between different versions of "System.IO.Pipelines" that could not be resolved. There was a conflict between "System.IO.Pipelines, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" and "System.IO.Pipelines, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51". "System.IO.Pipelines, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" was chosen because it was primary and "System.IO.Pipelines, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" was not.
I have checked NuGet Package Manager and can see that EfCore.TestSupport is the only package that references System.IO.Pipelines 6
Do you have any suggestions how to resolve this?
I'm not sure if this is an issue or this is the way you want it to show logs result.
STEP 1:
You run the comparer and you have this logs in error:
EXTRA IN DATABASE: ht->Table 'Address'
EXTRA IN DATABASE: ht->Table 'Customers'
EXTRA IN DATABASE: ht->Table 'Employees'
STEP 2:
Here are the logs:
DIFFERENT: Address->Property 'Address1', column type. Expected = nvarchar(max), found = nvarchar(200)
I would have expected something like:
EXTRA IN DATABASE: ht->Table 'Customers'
EXTRA IN DATABASE: ht->Table 'Employees'
DIFFERENT: Address->Property 'Address1', column type. Expected = nvarchar(max), found = nvarchar(200)
Entity:
public class Parameter
{
[DatabaseGenerated (DatabaseGeneratedOption.Identity)]
public int ParameterId { get; set; }
public ValueAggregationTypeEnum ValueAggregationTypeId { get; set; }
public decimal? NumericValue { get; set; }
}
public enum ValueAggregationTypeEnum : byte { Invariable = 1, Minimum = 2, Maximum = 3, Average = 4 }
protected override void OnModelCreating (ModelBuilder modelBuilder)
{
modelBuilder.Entity().Property (p => p.ValueAggregationTypeId).HasDefaultValue (ValueAggregationTypeEnum.Invariable);
}
SQL (SQL Server 2014):
CREATE TABLE [dbo].[Parameters] (
[ParameterId] INT IDENTITY (1, 1) NOT NULL,
[NumericValue] DECIMAL (9, 2) NULL,
[ValueAggregationTypeId] TINYINT DEFAULT ((1)) NOT NULL,
CONSTRAINT [PK_Parameters] PRIMARY KEY CLUSTERED ([ParameterId] ASC)
);
CompareEfWithDb returns:
DIFFERENT: Parameter->Property 'ValueAggregationTypeId', default value sql. Expected = , found = 1
Testing with EfCore.TestSupport 3.1.1 nuget package.
I don't see this listed in https://github.com/JonPSmith/EfCore.TestSupport/wiki/EfSchemaCompare-limitations,
It seems like it should be able to be treated similarly to a unique index, which is detected when missing.
Duplication:
CREATE DATABASE [FooDb]
GO
USE [FooDb]
GO
CREATE TABLE [dbo].[Foos](
[Id] [int] IDENTITY(1,1) NOT NULL,
[FooName] [nvarchar](450) NOT NULL,
CONSTRAINT [PK_Foos] PRIMARY KEY CLUSTERED ([Id])
) ON [PRIMARY]
GO
public class Foo
{
[Key]
public int Id { get; set; }
public string FooName { get; set; }
}
public class FooContext : DbContext
{
public FooContext(DbContextOptions<FooContext> options) : base(options) { }
public DbSet<Foo> Foos { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Test passes, but shouldn't if HasAlternateKey is used. EF generates in this case:
//CONSTRAINT [AK_Foos_FooName] UNIQUE NONCLUSTERED ([FooName] ASC)
modelBuilder.Entity<Foo>()
.HasAlternateKey(x => x.FooName);
//Test fails as expected if unique index configuration is used
//modelBuilder.Entity<Foo>()
// .HasIndex(x => x.FooName)
// .IsUnique();
}
}
public class FooTest
{
[Fact]
public void Blah()
{
//--------- Arrange ---------//
string connectionString = "Server=(localdb)\\mssqllocaldb;Database=FooDb;Trusted_Connection=True;";
var dbOptions = new DbContextOptionsBuilder<FooContext>().UseSqlServer(connectionString).Options;
var config = new CompareEfSqlConfig();
var comparer = new CompareEfSql(config);
using (var fooContext = new FooContext(dbOptions))
{
//--------- Act ---------//
var hasErrors = comparer.CompareEfWithDb(connectionString, fooContext);
//--------- Assert ---------//
Assert.False(hasErrors, comparer.GetAllErrors);
}
}
}
FYI postgres
is not always current role_name
using value returned from SELECT current_user;
might be more appropriate.
Hi Jon,
I'd like to be able publish my test project to run on a separate machine. As far as I can tell EfCore.TestSupport will only look for appsettings.json up a directory from the /bin folder the .dll lives in.
Does EfCore.TestSupport allow the appsettings.json to live anywhere else? If not, are you opposed to this? Do you have any thoughts on how I might go about changing this?
Thanks,
Andrew
After coming across your article:
Getting better data for unit testing your EF Core applications
I was looking forward to using your “Seed from Production” feature for EF Core 5.0 tests. But alas, you decided to leave that feature behind in EFCore.TestSupport v3.2.0.
Would it be possible to move that feature into a separate repository and NuGet package so that I could use that feature together with EfCoreTestSupport v5.0.0?
Thanks.
By the way, I found the first version of you book so helpful that I went and bought the 2nd versions as well.
Currently the EfSchemaCompare feature does not support the checking of alternate keys.
Here are the notes on how I might do it.
entityType.GetKeys()
methodUniqueConstraints
, which holds any non-foreign key, non-primary key, columns that have a unique constraint on them.Currently tests are failing becouse seems that library tries to call internal EF Core method that are not available now. Do you plan to update the library?
Microsoft.EntityFrameworkCore.Diagnostics.EventDefinitionBase.GetLogBehavior(Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger`1<!!0>)'.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.