EF6 localdb for integration testing - testing

I am developing a WPF application which requires some database access. For development purposes I am using localdb with database migrations enabled and EF6.
What I cannot figure out is how do I configure a separate localdb database for integration tests inside a VS2013 test project and run the database migrations to bring it up to date and then seed it with data.

Here's what I've ended up doing based off information from several sources. First, in the App.Config of my test project I've added the following
<connectionStrings>
<add name="YourContextName" connectionString="Data Source=(localdb)\mssqllocaldb;Integrated Security=true;AttachDBFilename=|DataDirectory|\databasename.mdf"
providerName="System.Data.SqlClient" />
</connectionStrings>
Then I created the following class:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.Entity;
using MyProject.Model.Entities;
using MyProject.Migrations;
namespace IntegrationTests
{
public class DatabaseInitializer : DropCreateDatabaseAlways<MyProjectDataContext>
{
}
[TestClass]
public class Initalize
{
[AssemblyInitialize]
public static void AssemblyInit(TestContext context)
{
AppDomain.CurrentDomain.SetData("DataDirectory", context.TestDeploymentDir);
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyProjectDataContext, Configuration>());
//Database.SetInitializer(new DatabaseInitializer());
}
}
}
My understanding is that this runs before each test run. The SetData call updates the |DataDirectory| used in the App.Config so that it is unique and doesn't try to use the same instance as the normal project.
From there I have the choice of either running the migrations and then supplying some test data as part of the test or to run an initializer that sets up the test data. Note that to run the migrations the configuration class generated by the migration must be changed from internal to public.
This seems to work so far. Not sure if this is the best way or if I can combine the migrations and then run a different seed for the tests.

Within your test project, you could set Database.SetInitializer() (or databaseInitializer within the project config file) with MigrateDatabaseToLatestVersion or with your own IDatabaseInitializer that calls DbMigrator.Update, and use a custom DbMigrationsConfiguration.
The test project could use a separate connection string for using LocalDB, and if the file referenced by your connection string's AttachDBFilename, then the initializer will try to create it.
Might be helpful: Recreate and Reseed LocalDb Before Each Unit Test
...But DropCreateDatabaseAlways won't work with EF6 migrations

Related

update Migration Command Fails for ConfigurationDbContext and PersistentGrantDbContext

I have been trying to get IdentityServer4 version 1.5.2 to work for a few days now without success. I am using VS2017
My Entity classes,DataContexts, repositories and migrations are resident in a .Net Standard Library (1.6). So far so good except when I run update-migration command for "PersistenGrantDbContext" and "ConfigurationDbCOntext". I get the error message
Could not load file or assembly 'System.Data.SqlClient, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
The datacontext classes that i created myself dont seem to have this problem after implementing "IDbContextFactory" interface
Here I have the implementation for the two culprits
public class TemporaryDbContextFactoryScopes : IDbContextFactory<PersistedGrantDbContext>
{
public PersistedGrantDbContext Create(DbContextFactoryOptions options)
{
var builder = new DbContextOptionsBuilder<PersistedGrantDbContext>();
builder.UseSqlServer("Server=-------;Database=-----------;Trusted_Connection=True;MultipleActiveResultSets=true",
optionsBuilder => optionsBuilder.MigrationsAssembly(typeof(UserDbContext).GetTypeInfo().Assembly.GetName().Name));
return new PersistedGrantDbContext(builder.Options, new OperationalStoreOptions());
}
}
public class TemporaryDbContextFactoryOperational : IDbContextFactory<ConfigurationDbContext>
{
public ConfigurationDbContext Create(DbContextFactoryOptions options)
{
var builder = new DbContextOptionsBuilder<ConfigurationDbContext>();
builder.UseSqlServer("Server=---------;Database=--------;Trusted_Connection=True;MultipleActiveResultSets=true",
optionsBuilder => optionsBuilder.MigrationsAssembly(typeof(UserDbContext).GetTypeInfo().Assembly.GetName().Name));
return new ConfigurationDbContext(builder.Options, new ConfigurationStoreOptions());
}
}
I have installed the latest version of System.Data.SqlClient still not working
Just wanted to share what I did to get things rolling. Not sure if that is the right approach though
First I did this in the class library .csproj
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.1" />
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="1.0.1" />
which turned out to be a bad idea because that was throwing out that error now without it running my migrations with my web app as my start up project return the error "Not context blah blah with name blah blah found"
So I realised contexts that I created myself worked without glitches so I did this for PersistentGrantDBCOntext and COnfigurationGrantDbContext
public class PGrantDbContext: PersistedGrantDbContext
{
public PGrantDbContext(DbContextOptions<PersistedGrantDbContext> options, OperationalStoreOptions storeOptions) : base(options, storeOptions)
{
}
}
and
public ConfigDbContext(DbContextOptions<ConfigurationDbContext> options, ConfigurationStoreOptions storeOptions):base(options,storeOptions)
{
}
and everything went smoothly.
Just not so sure if it is the right approach though
I was also in a similar situation few weeks ago and here's how I solved it.
Very similar to yours, I have two projects called Company.Identity (.NETCoreApp) as my Identity Project and Company.Identity.Data (.NETStandard 1.6) for migrations. I Use Company.Identity Project as the startup project for migration purposes as it is in the same solution as my data project and I didn't want to clutter the solution with yet another project just as a startup project for migrations.
I followed the tutorial in here.
The cli tool reference <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.1" /> is in my Company.Identity.csproj file.
I followed all the steps in the above tutorial except for the following difference
In ConfigureServices method in the Company.Identity Startup class, I have set the migrationsAssembly to Company.Identity.Data
var migrationsAssembly = "Company.Identity.Data";
Note that Company.Identity project has already got IdentityServer4.EntityFramework nuget package installed. This enabled me to add the migration for PersistedGrantDbContext. But when I tried to run migration for ConfigurationDbContext it gave me a build error. This was because the migrations generated for PersistedGrantDbContext requried IdentityServer4.EntityFramework nuget package. So I had to install that in the Company.Identity.Data project
I was able to add migrations using the following commands after above changes through command prompt in my Company.Identity project.
dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Migrations/IdentityServer/PersistedGrantDb -p ../Company.Identity.Data
dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Migrations/IdentityServer/ConfigurationDb -p ../Company.Identity.Data
Hope that helps
this may help you specially if you have docker-compose in your project. i was able to resolve this issue by removing the docker-compose project and then creating the migrations then adding it again.
https://stackoverflow.com/a/60320410/4977086

Migrations in separate assembly how to avoid hardcoded connection string?

I'm writing ASP.NET Core and Entity Framework Core application and I want to store my data access layer in separate assembly, so I followed this tutorial: http://www.michael-whelan.net/ef-core-101-migrations-in-separate-assembly/
But I would also like to avoid hardcoding connection string. I tried to store it in JSON config file or as environment variable and get it using ConfigurationBuilder but when using command line migration tool dotnet ef migrations none of these are available.
Is there any way to solve this problem? I'm using 1.0.1 versions of both .NET Core and EF Core.
To solve this issue I create a class library only for migration with a DbContext deriving from my DbContext but with hard connected connection string.
using Microsoft.EntityFrameworkCore;
namespace ChatLe.Repository.Identity.SqlServer
{
public class ChatLeIdentityDbContext: ChatLe.Models.ChatLeIdentityDbContext
{
public ChatLeIdentityDbContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=chatle;Trusted_Connection=True;MultipleActiveResultSets=true");
base.OnConfiguring(optionsBuilder);
}
}
}
Then I launch ef tool command like this :
To add a migration run dotnet ef --startup-project {path to my startup project} migrations add login-activity --context ChatLe.Repository.Identity.SqlServer.ChatLeIdentityDbContext
To upgrade the database run dotnet ef --startup-project {path to my startup project} database update --context ChatLe.Repository.Identity.SqlServer.ChatLeIdentityDbContext
Read the full sample on my git hub project : https://github.com/aguacongas/chatle/tree/develop/src/ChatLe.Repository.Identity.SqlServer

Automatically execute migrations when publishing ASP.NET Core app

Question
Is there any ways that I can automatically execute the migration code (EF 7) when publishing my ASP 5 application to IIS using Web Deploy?
I Tried
in the project.json, I added this code in the scripts:
"scripts" : {
"prepublish": ["dnx ef database update", "other commands..."],
"postpublish": ["dnx ef database update"]
}
none worked for me.
Additional Info
I followed the instructions on this link to deploy my ASP 5 RC-1 web application to IIS using web deploy.
After doing so in the publish settings I have:
Using web deploy in ASP 4 applications I have additional database options:
Use context.Database.Migrate()
You can call this from your Startup class:
using (var context = new MyContext(...))
{
context.Database.Migrate();
}
It will migrate your database to the latest version on application startup. But be careful doing it, maybe comment out this code and uncommend only when you want to run your migrations.
Apparently this process does not work now. https://github.com/aspnet/Home/issues/622 After you publish you should find the power shell script with the name of "profile name"-publish.ps1. Then add your commands below these three lines close to the end of this file. You might want to use powershell to make it easier to debug.
'Calling Publish-AspNet' | Write-Verbose
# call Publish-AspNet to perform the publish operation
Publish-AspNet -publishProperties $publishProperties -packOutput $packOutput
So I added the option -environment to my ef database command. Now it works:
"postpublish": ["dnx ef database update -e Staging"]
I have four different appsettings.json which different connection string for each environment. Just needed to indicate the environment for the command to work.
In you Startup.cs class add this code
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var context = serviceScope.ServiceProvider.GetService<AppDBContext>();
context.Database.Migrate();
}
}

Use web project config.json when doing integration testing

I am using ASP.NET 5 RC1 and I need to write integration tests ...
So on the Test project, ASPNET5_WEB_TEST, I have the following:
public class IntegrationTests {
private readonly TestServer _server;
private readonly HttpClient _client;
public IntegrationTests() {
_server = new TestServer(TestServer.CreateBuilder().UseStartup<Startup>());
_client = _server.CreateClient();
}
// Test methods ...
}
The Startup class is from the ASP.NET 5 project I am testing: ASPNET5_WEB
When I run the test I get the following error:
The configuration file 'C:\Projects\ASPNET5_TEST\config.json' was not found and is not optional.
I know I get this error because on Startup I have:
builder
.AddJsonFile("config.json", false)
.AddJsonFile($"config.{environment.EnvironmentName}.json", true);
To fix this error I need to copy, at least, config.json from my web project, ASPNET5_WEB, to my test project, ASPNET5_WEB_TEST. But this means I will need to maintain duplicate config.json or at least copy it every time I make a change.
Can't I tell TestServer to use Startup of the web project and also its config.*.json files?
And can I have a config.testing.json and set on the TestServer the environment to Testing so the Startup code uses config.json and config.testing.json?
I assume you're using the TestServer from aspnet, if so, it wasn't built to support the way you're config files are read. The TestServer is used to run simple integration tests for their "hosting engine" but not for integrations tests for a website.
Their ApplicationDeployerFactory class is what you can use however. Refer to this as an example of how to run an "integration" server. I've used selenium in conjunction with that to run integration tests against the project I'm working on atm.
Yes, you can.
Take a look at this issue https://github.com/aspnet/Mvc/issues/3410 and The mentioned package.
Basically you need to implement your own IApplicationEnvironment

How to use signalr v2 beta in asp.net mvc 4

Before v2:
RouteTable.Routes.MapHubs();
In v2, MapHubs does not exist anymore. The wiki says to add a Startup class and a Configuration method and a call to app.MapHubs().
namespace MyAssembly
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
//Before v2
//RouteTable.Routes.MapHubs();
app.MapHubs();
}
}
}
But the method is never called, no error occurs, and ... no hub are setup.
I suppose there is some code to add to global.asax.cs
What is the secret ?
Try defining [assembly : OwinStartup(typeof(MyAssembly.Startup))] to see if your Startup class is being picked up.
EDIT: removed lines not relevant.
Solution !
<appSettings>
<add key="owin:AppStartup" value="MyNameSpace.Startup, MyNameSpace" />
</appSettings>
plus update both MVC4 (not to prerelease, but to latest stable version) and SignalR/owin nugets.
plus fix bugs in js client :
if disconnectTimeout=999000 then it is disabled. Must be set server-side with: GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(999);
note: server side can not set a value < 6 (signalr throws an exception if DisconnectTimeout < 6). So use this magic number.
webSockets: set connection.socket = null in sockettransport, otherwise the call to start fails after a (manual) call to stop
serverSentEvents: prevent error caused by a reconnection attempt when the window is unloading
chrome fails with exception if signalr hub url not available (temporarily) : Instead of giving up try the next available protocol / try to reconnect.
I was able to get the 2.0 beta working by
Removing all references to the older version of SignalR, ie nuget uninstall of the library and double checking /bin
Installed SignalR 2.0.0-beta2 via Package Manager Console Install-Package Microsoft.AspNet.SignalR -Pre
Following the steps in the 1.x to 2.0 migration outlined here
And most importantly changing the project config to use Local IIS Web server instead of Visual Studio Developer Server (Cassini).
More info in the question/answer I posted here
In web.config there must be a fully qualified name of the class, e.g.
<appSettings>
<add key="owin:AppStartup" value="**My.Name.Space.Startup**, **AssemblyName**" />
</appSettings>
I had a problem when I put namespace instead of assembly name, but with the fully qualified name it works without any other changes to web.config!
UPDATE: I also followed the steps from the link: http://www.asp.net/vnext/overview/latest/release-notes#TOC13, i.e. removed a NuGet package "Microsoft.AspNet.SignalR.Owin"