Entity Framework Migration. How to create a Unit Test model to match the migration model?

I use continuous integration with TeamCity, NUnit and Git. I recently migrated (pardon pun) from FluentMigrator to Entity Framework Migrations. First of all, I did this to take advantage of the functionality of forests.

Nevertheless, you can potentially check some changes in the initial control without first changing the changes in the migrations (imagine a scenario in which the application was not executed before committing and clicking on the commit). I use a pre-tested business commit process , so I would like to detect this problem in the pre-testing , and not wait until migrate.exe is called (which would be too late in my workflow and break the "green repository").

My question is how to create a unit / integration test to determine when the migration model does not match the context model, so can I complete the assembly before trying to migrate it? Please note that I expect it to not match the database and would prefer not to access the database from the test.

I tried this approach:

[Test] public void CheckWhetherEntityFrameworkMigrationsContextIsUpToDate() { Assert.DoesNotThrow(() => { CallDatabase(); }); } private void CallDatabase() { using (var ctx = new MyContext("SERVER=(local);DATABASE=MyDatabase;Integrated Security=True;")) { var tenant = (from t in ctx.Tenant select t).FirstOrDefault(); } } 

But this will always fail if there are pending migrations (and not only if the migration model is not synchronized with the context model, which I do after that).

Update

I added the EntityFramework project to the EntityFramework project in this project. I hope they consider creating this method.

+6
source share
4 answers

Here is some code that will check if all changes to the model have been recorded in the migration or not.

 bool HasPendingModelChanges() { // NOTE: Using MigratorScriptingDecorator so changes won't be made to the database var migrationsConfiguration = new Migrations.Configuration(); var migrator = new DbMigrator(migrationsConfiguration); var scriptingMigrator = new MigratorScriptingDecorator(migrator); try { // NOTE: Using InitialDatabase so history won't be read from the database scriptingMigrator.ScriptUpdate(DbMigrator.InitialDatabase, null); } catch (AutomaticMigrationsDisabledException) { return true; } return false; } 
+3
source

If anyone finds this useful, I am testing migration by doing all of them in a test database using the following code:

 [TestClass] public class MigrationsTests { [TestMethod] public void RunAll() { var configuration = new Configuration(); var migrator = new DbMigrator(configuration); // back to 0 migrator.Update("0"); // up to current migrator.Update(); // back to 0 migrator.Update("0"); } } 

This checks all Up and Down migrations, as well as detecting pending changes when disabling automatic migration.

NOTE. Make sure you run this for the test database. In my case, the app.config test project has a connectionString in the test database (only a local SQLExpress instance).

+11
source

I wanted to get the best of all the answers here so far, so here is what I came up with:

 [TestClass()] public class MigrationsTests { [TestMethod()] public void MigrationsUpDownTest() { // Unit tests don't have a DataDirectory by default to store DB in AppDomain.CurrentDomain.SetData("DataDirectory", System.IO.Directory.GetCurrentDirectory()); // Drop and recreate database Database.SetInitializer(new DropCreateDatabaseAlways<BoxContext>()); BoxContext db = new BoxContext(); db.Database.Delete(); // Make sure it really dropped - needed for dirty database db.Database.Initialize(force: true); var configuration = new Migrations.Configuration(); var migrator = new DbMigrator(configuration); // Retrieve migrations List<string> migrations = new List<string> { "0" }; // Not sure if "0" is more zero than the first item in list of local migrations migrations.AddRange(migrator.GetLocalMigrations()); try { migrator.Update(migrations.First()); for (int index = 0; index < migrations.Count; index++) { migrator.Update(migrations[index]); if (index > 0) migrator.Update(migrations[index - 1]); } migrator.Update(migrations.Last()); } catch (SqlException ex) { Assert.Fail("Should not have any errors when running migrations up and down: " + ex.Errors[0].Message.ToString()); } // Optional: delete database db.Database.Delete(); } [TestMethod()] public void PendingModelChangesTest() { // NOTE: Using MigratorScriptingDecorator so changes won't be made to the database var migrationsConfiguration = new Migrations.Configuration(); var migrator = new DbMigrator(migrationsConfiguration); var scriptingMigrator = new MigratorScriptingDecorator(migrator); try { // NOTE: Using InitialDatabase so history won't be read from the database scriptingMigrator.ScriptUpdate(DbMigrator.InitialDatabase, null); } catch (AutomaticMigrationsDisabledException) { Assert.Fail("Should be no pending model changes/migrations should cover all model changes."); } } } 

A couple of things worth noting:

  • You need to install the Entity Framework in a test project.
  • You need to add [assembly: InternalsVisibleTo("MyTestsProject")] at the beginning of your Configuration class
  • You need to specify the Entity Framework connection string in App.config , which is intended only for the test project, since the database will be deleted and updated frequently - if you need to remember on the machine with the machine that parallel runs can lead to conflicts, so you can want to change the row for each assembly
+3
source

I think this works better than the Pablo Romeo code. This updates and then again undoes one step to catch missing elements in downgrade scripts.

 [TestFixture] class MigrationTest { [Test] public void RunAll() { var configuration = new Configuration(); var migrator = new DbMigrator(configuration); // Retrieve migrations List<string> migrations = new List<string> {"0"}; // Not sure if "0" is more zero than the first item in list of local migrations migrations.AddRange(migrator.GetLocalMigrations()); migrator.Update(migrations.First()); // Doe een stapje naar voren, en een stapje terug (www.youtube.com/watch?v=2sg1KAxuWKI) // (Dutch pun) meaning: take a small step forward, and a small step back ;) for (int index = 0; index < migrations.Count; index++) { migrator.Update(migrations[index]); if (index > 0) migrator.Update(migrations[index - 1]); } migrator.Update(migrations.Last()); migrator.Update(migrations.First()); } } 
+2
source

Source: https://habr.com/ru/post/955635/


All Articles