Running Unit Test on ASP.Net MVC5 with DbContext - c#

I currently using Unit Testing on my projects but it seems I have trouble on getting the data on my site DBContext, I assume that I need to run the web project then run the test but I dont think Visual Studio permits that.
So I tried opening 2 instances of Visual Studio but it still did not work.
This is my code:
private ApplicationDbContext db = new ApplicationDbContext();
[TestMethod]
public void IsDbNull()
{
var dblist = db.StudentInformation.ToList();
Assert.IsNotNull(dblist);
}
A simple assert to check if the project can read my database, I tried debuging and dblist doesn't have any items on it.
I saw some codes that uses fake database by putting it as CSV but as much I dont want to go that method since I want to test the real data itself.
I also saw "Run Tests" on GitHub but it only supports VS 2012

Putting aside discussions about what constitutes a unit test, as has been suggested by #jdphenix in the comments, your problem is likely to be a configuration issue. The main evidence for this comes from your statement:
I tried debuging and dblist doesn't have any items on it.
If your test code had failed to connect to a database, you would get an exception when attempting to read the contents from it rather than an empty list, which is what you are reporting.
In response to your comment:
If I make the configuration in the test project then I will need to replicate the database which is pointless because its a Unit Test. Its purpose is just to test the main project not to have its own configurations
When using entity framework, if you don't supply it with configuration information, it will derive a connection string based on the namespace and class name of the context you are using to connect with the database (I believe it will also assume you want to use SQLEXPRESS as the provider, although that may be version dependant). If you don't provide configuration information in your unit-test project, this is what the entity framework will do. If you don't have any configuration in your application then the two will match, and everything will point at the same database.
In most real world applications however, your application will have some kind of connection information in it. This will either be because you want a sensible database name, or you need to be able to control the machine that the database is on, or you need to use a different provider. If this is the case then you need to replicate the connection string into your test project. Note, duplicating the connection string does not "replicate the database", it simply creates another pointer to the database.
It's also worth noting that if there is a mismatch in the test project, EF will try to create a new database with it's defaults if one doesn't already exist.
A simple way to check if it is a configuration issue is to debug your test and real code and compare the values of:
(((System.Data.Entity.DbContext)(db)).Database.Connection).ConnectionString
Where db is the instantiated name of your database context (note you'll have to execute a line like db.StudentInformation.ToList() before it is populated.
As you appear to be using the MS test framework, any configuration you need to be available for testing should be placed in an App.config file in the project (which may already have been added if you used nuget to reference the entity framework) to make it available (note, this varies with different testing frameworks and may also be different if you're using a non-standard test runner).

Related

VS is storing my data in some other database?

Visual studio creates a new database out of thin air to store my data. This is my DbContext:
public class LinkedDataContext : DbContext
{
public DbSet<LinkedData> LinkedData { get; set; }
}
No errors are being thrown, I just end up with another database that is only visible through the SQL Server Object Explorer unlike my initially created database which is the top one in the screenshot.
Edit
I migrated the whole accounts database generated by the MVC project to the MSSQL 2014 server. I simply added a database there and changed the connection string, then it automaticaly populated the database with the needed tables.
So I created my custom table, exactly as it was in the local database. I removed the local databases, the other connection strings and the Controller. Then I rebuild my project and created the controller again. But VS/MVC/EF or whomever is responsible is still creating a local database for my custom data.
When I create the controller it seems to find my table in MSSQL SERVER 2014, otherwise I would get a safe dialogue to store the sql file locally. So what is really happening here? Like I said, the account functionality worked instantly like a charm. My custom table in MSSQL simply won't get used.
EDIT
So I set the DefaultConnectionFactory in Web.config to my MSSQL SERVER 2014 and now it is generating a new Database inside my MSSQL SERVER. It seems to be the namespace, when I create a controller I need to pass in the namespace for the both the Model class and Context class.
Model class: LinkedData (DataVisualization.Models)
Data context class: LinkedDataContext (DataVisualization.Models)
The databases that keep getting generated automatically to hold my custom data are called: DataVisualization.Model.LinkedDataContext.
Does anyone have any idea what is really going on here?
I believe it is just the connection string in your Web.config. When you create a DbContext from an existing database outside of your project, Visual Studio prompts
The connection you selected uses a local data file that is not in the
current project. Would you like to copy the file to your project and
modify the connection?
If you select Yes, this copies the database file into your project, sets its Build Action to Content, sets a relative reference to it in your connection string and sets it to copy to your output directory on build.
If you modify the connectionString in your Web.config to point to the correct database you should be set (for future reference, answer No when asked if you want to copy it, unless that is really what you want to do - e.g. for a database file you're distributing with your binaries).
As an example, see the two connections listed below. You would see something like ProjectContext if you selected Yes, or something like ExternalContext if you selected No.
<connectionStrings>
<add name="ProjectContext" connectionString="data source=(LocalDB)\MSSQLLocalDB;attachdbfilename=|DataDirectory|\Database.mdf;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
<add name="ExternalContext" connectionString="data source=(LocalDB)\MSSQLLocalDB;attachdbfilename=C:\Programming\.Net\DataVisualization\Data\DataVisualization\App_Data\Database.mdf;integrated security=True;connect timeout=30;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>
Note that the actual syntax of the connectionString may be different in your app depending on settings used, but the key part is the |DataDirectory| reference vs the correct path. The path is what you'd need to modify.
The shorthand solution is this:
public class LinkedDataContext : DbContext
{
public DbSet<LinkedData> LinkedData { get; set; }
public LinkedDataContext() : base("DefaultConnection")
{
}
}
I was assuming it would take the default connection if there was no connection named after the context. The reason was that I did not get a error so the connections would have been fine. Yet without specifying a connectionString in web.config it just seem to take part of the default string, since it does find my database and throws in it's namespace and creates a new database out of thin air. I might be new to MVC but I find this ridiculous default behavior. So I still have no clue what the idea behind this is.
Unless you want to have a couple of hundred connection strings for a fairly sized application the only way to go seems to be to call the parent constructor and specify the DefaultConnection there. Kind of ironic you have to "specify" default behavior.
Unlike what #tomtom told me, in almost 10 hours I did not find a single scenario that resembles mine. Maybe I was not clear but in my initial post I did specify each step I took. Using a MSSQL SERVER does not seem to be necessary.
Hope this helps someone else out.
STANDARD BEHAVIOR. As bad as it is. Your db template is copied to the runtime every time you hit the "debug" button, so you always start with a new datababase. Painfull as hell. Not sure how other's solve this - I never use this side of visual studio, I have a sql server installed and create my databases there manually. Makes sure i am always working against a defined copy. Obviously VS has no rights to create databases there ;)
If you bother using google or the site search a little you find tons of similar questions - this is a standard problem people regularly get trapped in because it is totally not what they expect.
(if you ask me, the whole db maintenance side of EF is broken anyway, including the "migrations" that hardly can use SQL Server most basic features).

Do I need a migration for EF code first when the database does not exist in SQL Azure?

I have tried lots of variations of EF migration v6.0.1 (from no database, to empty databases to existing databases) and I have a particular problem with Azure DB instances not being able to correctly be created on first deploy using Octopus deploy.
There are a number of places where this could be going wrong, so I thought I would check some basics of EF Code First migration with you fine people if I may:
If I create a code-first model, and know that the database does not exist in the intended target database server on Azure. With the default of 'CreateDatabaseIfNotExists' approach and with AutomaticMigrations disabled;
If I then call 'migrate.exe' with the assembly containing my DbContext and migration Configuration will I get a new database created with the current state of the model? or will I get a new database with nothing in it? i.e. do I need to explicitly 'add-migration' for the initial state of the model?
I have read in the documentation that the database instance should be created automatically by the migration process, but no one states clearly (at least to me) that this newly created database will be generated with the current model without a formal 'initial state' migration created.
So the question is this: do I need an explicit migration model generated for migrate.exe to work from?
Through whatever means I try, I get a database but the application launches with the unfriendly message "Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations." Remembering that this is the same application library that just created the database in the first place (from scratch) I fail to understand how this has happened!
I did manually delete the target database a few times via SQL Server management studio, is this bad? Have I removed some vital user account that I need to recover?
Migrations and the Database Initializer CreateDatabaseIfNotExists are not the same.
Migrations uses the Database Initializer MigrateDatabaseToLatestVersion, which relies upon a special table in the database _MigrationsHistory.
By contrast, CreateDatabaseIfNotExists is one of the Database Initializers which relies upon the special database table EdmMetadata. It does exactly as it implies: Creates a database with tables matching the current state of the model, i.e. a table for each DbSet<T>, only when the database does not exist.
The specific error you have quoted here, Model compatibility cannot be checked because the database does not contain model metadata., occurs due to the existence of DbSet<T> objects which were added to the code base after the initial database creation, and do not exist in EdmMetadata.
There are 4 basic Database Initializers available, 3 of which are for use when migrations is not being used:
CreateDatabaseIfNotExists
DropCreateDatabaseWhenModelChanges
DropCreateDatabaseAlways
Also note, the 4th Initializer, MigrateDatabaseToLatestVersion, will allow you to use Migrations even if AutomaticMigrations is disabled; AutomaticMigrations serves a diffierent purpose, and does not interact with the Database Initializers directly.
If you intend to use Migrations, you should change the Database Initializer to MigrateDatabaseToLatestVersion and forget about the other 3. If, instead, you intend to not use Migrations, then the choice of Initializer is situational.
CreateDatabaseIfNotExists will be more appropriate when you are certain that your data model is not undergoing active change, and you only intend to be concerned with database creation on a new deployment. This Initializer will elp ensure that you do not have any issues with accidental deletion of a database or live data.
DropCreateDatabaseWhenModelChanges is most appropriate in development, when you are changing the model fairly often, and want to be able to verify these changes to the model. It would not be appropriate for a production server, as changes to the model could inadvertently cause the database to be recreated.
DropCreateDatabaseAlways is only appropriate in testing, where your database is created from scratch every time you run your tests.
Migrations differs from these 3 Database Initializers, in that it never drops the database, it instead uses Data Motion to execute a series of Create Table and Drop Table SQL calls.
You also can use Update-Database -Script -SourceMigration:0 in the Package Manager Console at any time, no matter which Database Initializer you are using, to generate a full SQL script that can be run against a server to recreate the database.
Firstly, many thanks to Claies who helped me get to the bottom of this problem. I have accepted his answer as correct as ultimately it was a combination of his response and a few additional bits of reading that got me to my solution.
In answer to the actual posts question 'Do I need a migration for EF code first when the database does not exist in SQL Azure?' the answer is yes you do if you have disabled automatic migrations. But there is a little more to be aware of:
The Azure aspects of this particular problem are actually irrelevant in my situation. My problem was two-fold:
The migration being generated was out of sync with respect to the target model. What do I mean? I mean, that I was generating the migration script from my local database which itself was not in sync with the local codebase which created a migration that was incorrect. This can be seen by comparing the first few lines of the Model text in the __MigrationHistory. This awareness was helped by referring to this helpful post which explains how it works.
And more embarrassingly (I'm sure we've all done it) is that my octopus deployment of the web site itself (using Octopack) somehow neglected to include the Web.Config file. From what I can tell, this may have occurred after I installed a transform extension to Visual Studio. Within my nuget package I can see that there is a web.config.transform file but not a web.config. Basically this meant that when the application started up, it had no configuration file to turn to, no connections string at all. But this resulted in the slightly misleading error
Model compatibility cannot be checked because the database does not
contain model metadata.
Whereas what it should have said was, there isn't a connection string you idiot.
Hopefully this helps people understand the process a little better after reading Claies answer and also that blog-post. First though, check you have a web.config file and that it has a connection string in it...

Entity Framework on .mdf file

I am working on some project at the moment and I have to use local database. So, I created a new service-based database (no tables atm). Then I wanted to add Entity Framework support.
Because I never used Entity Framework before, I was referring to that link: http://msdn.microsoft.com/en-us/data/jj200620.aspx.
Everything is OK, but here it gets complicated. I created my DataContext class with DbSet inside it. But, when I run my unit test, table is created on Localdb (not inside my .mdf file).
What to do?
I am pretty sure, that I did choose which database to use correctly (actually did that 3 times already), but still, data tables are created on LocalDb. What I am doing wrong here?
I am complete beginner with that (been only using doctrine ORM). Otherwise I can insert data and all, it is just on the wrong database.
When your doing code first development in EF, you can force EF to only ever consider one connection string name.
One of the constructors (of which there are quite a few overloads) on the EF Data Context parent classes, takes a simple string.
This string is given to be the name of a connection string in the App or Web config to use.
You make the call something like this:
using System.Data.Entity;
namespace MSSQL_EFCF.Classes
{
public class DataAccess : DbContext
{
public DataAccess() : base("myConnectionString")
{}
public DbSet<MyTableObject> MyObjects { get; set; }
}
}
You can still put any code you need for your own start-up (Such as DB Initializer calls) inside your constructor, and all that will get called once the base call completes.
The advantage of doing things this way forces entity framework to always use the named connection string and never anything else.
The reason this catches many developers out, and why it runs off an uses localdb is deceptively simple.
The Entity Framework DbContext by default will use the name of the data context derived class as a database name, and if it can't find a suitable connection string in any config file by that name, makes the assumption that your working in development mode without a full backing data store.
In my example above, EF would examine App and/or Web.config for a connection string called "myConnectionString"
Once it makes this development decision, it knows that localdb will be present as this gets installed with the latest builds of visual studio, and so it will automatically seek out a connection and populate it with a db that follows the name of the context in which it's used.
I've previously written a blog post on the subject, which you can find here :
http://www.codeguru.com/columns/dotnet/entity-framework-code-first-simplicity.htm
NOTE: The above applies to any database that you connect with using EF, it's the connection string that decides what/where the actual data store is.

How to seed database data for integration testing in C#?

I've been writing some integration tests recently against ASP.Net MVC controller actions and have been frustrated by the difficulty in setting up the test data that needs to be present in order to run the test.
For example, I want to test the "add", "edit" and "delete" actions of a controller. I can write the "add" test fine, but then find that to write the "edit" test I was am either going to have to call the code of the "add" test to create a record so that I can edit it, or do a lot of setup in the test class, neither of which are particularly appealing.
Ideally I want to use or develop an integration test framework to make it easier to add seed data in a reusable way for integration tests so that the arrange aspect of an arrange/act/assert test can focus on arranging what I specifically need to arrange for my test rather than concerning itself with arranging a load of reference data only indirectly related to the code under the test.
I happen to be using NHibernate but I believe any data seeding functionality should be oblivious to that and be able to manipulate the database directly; the ORM may change, but I will allways be using a SQL database.
I'm using NUnit so envisage hooking into the test/testfixture setup/teardown (but I think a good solution would potentially transferable to other test frameworks).
I'm using FluentMigrator in my main project to manage schema and seeding of reference data so it would be nice, but not essential to be able to use the FluentMigrator framework for a consistent approach across the solution.
So my question is, "How do you seed your database data for integration testing in C#?" Do you execute the SQL directly? Do you use a framework?
You can make your integration testing on Sql Server Compact, you will have a .sdf file and you can connect to it giving the file's path as connection string. That would be faster and easier to setup and work with.
Your integration test would not probably need millions of rows of data. You can insert your test data into your database and save it as TestDbOriginal.sdf.
When you are running your tests, just make a copy of this 'TestDbOriginal.sdf' and work on that copy, which is already seeded with data. If you want to test a specific scenario, you will need to prepare your data by calling some methods like add, remove, edit .
When you go production or performance testing, switch back to your original server version, be it Sql Server 2008 or whatever.
I don't know if it's necessarily the 'right' thing to do, but I've always seeded using my add/create method(s).

Moving Entity Framework model into class library from web project

I am using Entity Framework and recently came to realize the benefits of having your EF model in another project within the same solution so that I can build multiple UIs from it.
I moved it over to a new class library project and updated all the references to the entities in the web project to use the new dll generated by the project. Everything has gone smoothly, except for one small snag. When I moved EF over to the new project, somehow it was still reading its connection string from the web.config in the web project (don't ask me how because I have no clue).
I used "Update Model from Database" in the EF designer and it did not find a connection string (as I expected after moving it over to the new project) so I used the wizard to generate a new connection string, which it did just fine. The new connection string now resides in App.config within the class library project. The connection string in the properties window is correct now, and the designer is reading it from the App.Config. I went ahead and deleted the connection string from Web.Config in the web project.
Now when running the application I get the following error:
The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.
If I paste the connection string back into the Web.Config it all works just fine. I do not want to create a new EF model from scratch because it is a fairly complicated model and I did a lot of restructuring after pulling in from the DB. I have poured over the generated CS file as well as the XML in the edmx file and cannot find anything useful. Any help is much appreciated. Obviously for now, until I figure this out, I'm just leaving the connection string in web.config since, for whatever reason, that seems to work.
This is by design; while the config file in the class library is what the designer will use, the configuration file of the actual application is what will get used at runtime. Whether that's Web.config for an ASP.NET project or App.config for a Winforms or WPF project, it's the application configuration file (or something higher up, like Machine.config) that will be used; the file in the class library is not part of the application.
If you're trying to provide an EF model that will work without having to specify the connection string in the application or web configuration file, then you'll have to store the connection string some other way (you could always hard-code it) and pass it into the appropriate overload of your context's constructor.
My solution is generally to provide a static parameterless function on the context itself that calls this overload with the appropriate connection string.

Categories

Resources