Can TransactionScope rollback be used with Selenium or Watin? - c#

I am trying to do some automated web testing of my ASP.NET application. I was hoping to use the AutoRollback attribute from Xunit.net extensions to undo any database changes that were made during the test. AutoRollback uses TransactionScope to start a transaction before the test and roll it back afterwards.
When I try to hit my web application during a transaction, it always times out. It seems like this should work, any ideas? Here is my test:
[Fact]
[AutoRollback]
public void Entity_should_be_in_list()
{
Entity e = new Entity
{
Name = "Test",
};
dataContext.Entities.InsertOnSubmit(e);
dataContext.SubmitChanges();
selenium.Open("http://localhost/MyApp");
Assert.True(selenium.IsTextPresent("Test"));
}

Your ASP.NET application has a separate database context and it has no idea that you want it to join transaction started by Xunit.net. Apparently, the database locks some resources when transaction starts; web application waits patiently for some time and eventually gives up.
I think your best bet is to start from empty database and use SQL script to create schema and populate lookup tables (your database is under source control, right?). Another approach is to backup database before running the tests and then restore it once they finish.

Related

Where should I put Database.EnsureCreated?

I have an Entity Framework Core + ASP.NET Core application and when my application starts up I want to ensure that the database is created, and eventually (once I have migrations) I want to ensure that those are also run.
Initially I put Database.EnsureCreated() into the constructor of my DbContext but that appears to run every time someone hits my application since a new instance of the DbContext is created each time.
I tried to put it into my startup code, but I need an instance of my DbContext to do that and it is unclear how exactly to get one. I am configuring EF as so:
serviceCollection.AddEntityFramework()
.AddSqlServer()
.AddDbContext<Models.MyContext>(options => options.UseSqlServer(...));
I don't see a way to get an instance of the DbContext from the service collection, and I don't see any appropriate singleton to inject a DbContext into so I can do some one-time initialization.
So what is the best place to ensure some code related to my DbContext is called once per application run?
At the time of this writing, there is not a "correct" place to run code on application startup such that it executes within the request scope (see https://github.com/aspnet/Hosting/issues/373).
For now, the workaround is to do the following, but it won't work in more complex multi-application scenarios (see https://github.com/aspnet/EntityFramework/issues/3070#issuecomment-142752126)
public class Startup
{
...
public void Configure(IApplicationBuilder applicationBuilder, ...)
{
...
// NOTE: this must go at the end of Configure
var serviceScopeFactory = applicationBuilder.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
using (var serviceScope = serviceScopeFactory.CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetService<MyDbContext>();
dbContext.Database.EnsureCreated();
}
}
}
I wonder why you would run to run EnsureCreated as part of your service anyway. Do you really want your webserver to create or update the database schema? Why would the webserver be up and serving request if the database is not up to date?
Do you really trust your migrations so much that they don't ruin data when executed, that you don't want to test the data after running them?
In addition, this will require you to give the webserver database user permissions to change the database schema. This is a vulnerability in itself - someone taking over your webserver will be able to modify your database schema.
I suggest you create the database and apply migrations in a small utility you run yourself, not as part of your web application.
I think zmbq's suggestion is a correct one and there is a way to ensure that migrations are run along with the deployment, so that binaries and database changes are in sync, using Visual Studio's Publish functionality.
When publishing against an IIS instance, one can specify target database connection string to use to also run required migrations:
This will ensure that changes are applied only when needed (not every time application starts) and that application runs using the least required database rights (i.e. database writer, reader etc.) as opposed to rights to alter tables, create indexes etc.

Rollback changes made to Database in Entity Framework .NET

I am writing unit test cases for testing a framework. The unit test adds and modifies the data in an existing database. I need to rollback all the changes done to database after a test finishes, i.e. delete the rows added and revert the rows modified.
I am using Entity Framework 6 for accessing the database. The underlying database is SQL Server. Is there any support provided by EF6 to achieve this?
Presently I am storing the changes in a list and I refer the this list for cleaning up the database. But using this approach leaves some residue randomly. I am not sure of the reason though, maybe some race condition or something.
Looking for some minimal and smart alternative for it. Thanks in advance :)
you can wrap your test in a transaction and don't commit changes:
using (TransactionScope scope = new TransactionScope()) {
//do your stuff
}
But for unit testing propouses you can use Effort - Entity Framework Unit Testing Tool which provide in-memory database operations.
EDITED to reply last comments
You can use an overloaded TransactionScope contructor to control the IsolationLevel, so you can choose to read uncommited changes or not.
If your proxy isn't inside the Transaction, please, check that the connection string is the same, so ado.net can identify the connection and enlist the connection in the same transaction.
If the connection string is not the same, you probably will need to activate the Distributed Transaction Coordinator. Here you have an explanation how DTC scalation occurs: TransactionScope automatically escalating to MSDTC on some machines?

How to stop EntityFramework migrations from creating my schema automatically?

All right, I'm using EntityFramework migrations, and they work fine, but when I run my application, (Web API) and the first time the context is used, the schema is created automatically for me. I DO NOT want that. I'd like to see an exception specifying that the tables do not exist or something like that.
In my configuration class I have something like this:
this.AutomaticMigrationsEnabled = false;
I thought that was going to be enough but EntityFramework keeps re-creating my database schema.
Since I'm using a Continuous Integration and Continuous Delivery process I want to use EF migrations to create the scripts for me and just check in my scripts and the scripts will be executed against the database for me (I already created that process)
So how can stop EntityFramework migrations for trying to create my database schema automatically when the application runs (when the context is accessed the first time in the AppDomain)?
Unset the database initializer for your context.
Database.SetInitializer<MyContext>(null);

Close database connection in MSSQL server

I am writing integration tests to verify the behaviour in my repositories. The problem I run into is that I want to start with a clean database for every test. I managed to do so by writing the SetUp as follows:
[SetUp]
public void SetUp()
{
_applicationContext = new TestApplicationContext();
_applicationContext.Database.Connection.Close();
_applicationContext.Database.Delete();
_applicationContext.Database.Create();
_tenantRepository = new TenantRepository(_applicationContext);
_userRepository = new UserRepository(_applicationContext);
}
The TestApplicationContext sets the database name to TestDatabase.
This works fine until I want to check the actual database for the result of my test. Then I make a connection from MSSQL server to the same database, which won't close until I either:
shut down MSSQL server
delete the database with the option "close all connections"
The only way I found is via SQL commands. Maybe it's because of my n00b knowledge regarding MSSQL, but I was kinda hoping for a "close connection" button / option.
How can I close the connection to the database from MSSQL server?
Or, is there a way I can do this programmatically from C#?
UPDATE:
Maybe I wasn't very clear. But the test SetUp fails after I opened MSSQL and viewed the contents of a table. This is because MSSQL also creates a connection to the TestDatabase, and my integration test is not able to close that connection. So I am looking for a solution that allows me to close the connection I created from MSSQL server.
You can work around the connection problem if instead of dropping and re-creating whole database you just drop and re-create selected (or all tables).
You could create little script that will do it for you in a way that you do not need to hard-code table names:
http://www.apexure.com/blog/2010/07/29/delete-all-tables-in-sql-server-database/
Alternatively, Julia Lerman in her book "Programming Entity Framework: Code First" mentiones this approach in more mature form, as incorporated as a custom database initializer:
As well as writing your own custom initializers, you can also find
initializers that other people have created. One example of this is
available in the EFCodeFirst.CreateTablesOnly NuGet package. This
initializer will allow you to drop and create the tables in an
existing database, rather than dropping and creating the actual
database itself. This is particularly useful if you are targeting a
hosted database where you don’t have permission to drop or create the
entire database.
You're releasing the connection back to the connection pool, not actually closing it. Instead of creating/deleting the database for each test, begin new transaction in setup and rollback in cleanup. This way no changes will be committed to your database and your test will always start from a clean state.
Also, because you are testing against live database, I wouldn't call your tests "unit" tests. Unit tests do not have any external dependencies.
The only way to reliably get an exclusive lock on a database is to use the SINGLE_USER WITH ROLLBACK IMMEDIATE technique. I recommend that you create a database snapshot with an empty state and restore to that snapshot each time. That will be much faster.

Entity Framework savechanges - can't see changes in other clients

I'm using EF 4.0 with VS2010. I have 2 clients running my applicaion.
When I save the changes in one client, I see them in the SQL server, but the 2nd client doesn't see them.
I need to restart the application to see the changes.
I'm using a Data layer for all the DB stuff, I leave my connection open all the time (as suggest in some post I read) might it be the problem??? any workaround I can't write the DL from scratch again.
10x
By default if an entity is loaded to the context that instance is returned when you query the database for a set of entities which will include the above entity.
You need to set the MergeOption to OverwriteChanges to get the changes in the database.
context.Products.MergeOption = MergeOption.OverwriteChanges;
var products = context.Products.Where(/**/);
Its better to create short lived to contexts to avoid such problems.
EntityFramwork isn't updating data when you change it on other connection. To get new state you have to recreate Context and load all data again.

Categories