2

I am running some integration tests against a database. I want to setup the database with seed data, run my tests, and then delete the database for every test (so each test has a fresh slate). I'm currently using these setup/teardown methods to do it:

private ProjectDbContext db;

[TestInitialize]
public void SetUp()
{
    db = new ProjectDbContext("TestConnection");
    (new SeedData()).Run(db); //Seed Data
}

[TestCleanup]
public void Teardown()
{
    db.Database.Delete();
    db.Dispose();
}

My problem is that it takes a little over a half second per test and I'd like to see better performance. Any thoughts? Anyone have a better strategy?

orourkedd
  • 6,201
  • 5
  • 43
  • 66

2 Answers2

0

You could do something like:

public static void ClearDatabase(DbContext context)
{
    var objectContext = ((IObjectContextAdapter)context).ObjectContext;
    var entities = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace).BaseEntitySets;
    var method = objectContext.GetType().GetMethods().First(x => x.Name == "CreateObjectSet");
    var objectSets = entities.Select(x => method.MakeGenericMethod(Type.GetType(x.ElementType.FullName))).Select(x => x.Invoke(objectContext, null));
    var tableNames = objectSets.Select(objectSet => (objectSet.GetType().GetProperty("EntitySet").GetValue(objectSet, null) as EntitySet).Name).ToList();

    foreach (var tableName in tableNames)
    {
        context.Database.ExecuteSqlCommand(string.Format("DELETE FROM {0}", tableName));
    }

    context.SaveChanges();
}

If you have no constraints and it's important that identity columns are set a certain way for your tests (which I'd recommend against), you could use TRUNCATE instead of DELETE FROM.

(code for deletion from here.)

Community
  • 1
  • 1
antinescience
  • 2,339
  • 23
  • 31
  • Sorry, my laptop was dying as I was typing that and I wanted to make sure I got it in beforehand. You'd have to make sure the database persisted between tests and was ONLY created if it didn't exist (to ensure tests could run atomically but also in sequential order). The way we do it is to have fixtures that inherit from an abstract class that has a property for the DB. So you check to see if the DB is null - if it is, create it, if not, just reseed data. – antinescience Mar 24 '13 at 03:27
  • Hell, if you wanted to speed it up even more, you could have tableNames be a property on the abstract as well - set it once so you don't have to go through reflection every time you do teardown. – antinescience Mar 24 '13 at 03:29
  • Thanks! I was thinking of something more along these lines. I'll have to make sure they are ordered correctly. – orourkedd Mar 24 '13 at 03:31
0

According to your code, I understand that you want to delete the data you inserted into the database for testing. I have done it in slightly different way but it might be helpful to you. We can use TransactionScope instead of deleting the data manually. Image of codeUsing TransactionScope in TestMethod You can also visit here for details of the approach.

Foyzul Karim
  • 4,252
  • 5
  • 47
  • 70