1

When researching EF & Code First, I asked a question a while ago (ref this thread) reguarding how you keep your tests from overlapping each other. I want to seed the DB and was doing it like this for each test class (using MSTest):

  public class CustomerSmokeTests {
    private const string CONNECTION_STRING = "server=localhost;database=CPT_CustomerDataSync_SmokeTests;uid=sa;pwd=Password1!;";

    private DatabaseFactory _dbfactory;
    private CustomerCacheContext _customerContext;

    [TestInitialize]
    public void Setup() {
      // set initializer to create new DB
      Database.SetInitializer(new SmokeTestCreateDbWithDataIfNotExists());
      Database.SetInitializer(new SmokeTestDropCreateDbWithDataAlways());

      // create new DB connection to local SQL Server
      _dbfactory = new DatabaseFactory(CONNECTION_STRING);

      // connect to DB to auto generate it
      _customerContext = _dbfactory.GetDataContext();
    }

    [TestCleanup]
    public void Cleanup() {
      _customerContext.Dispose();
      _dbfactory.Dispose();
    }

    // tests
}

However the issue here is that each test creates/tears down the DB (not ideal as they overlap each other and fail... if you run the tests individually they all pass as desired... plus this greatly slows down the tests).

A good solution was to instead wrap them up in TransactionalScopes, however I'd like to ensure at the start of a test run, the DB is regenerated using the seed info (as the seed changes as tests are developed by my devs).

A brute force way to do this would be to create some sort of handler that in the test init, it would check to see if the DB was recently created and if not, create it with the seed info. If not, it would ignore that step. Then it would create a TransactionalScope() that would be rolled back in the test cleanup.

But is there a better way to handle this? Got the over-engineering feel with this brute force appraoch... ideas?

Community
  • 1
  • 1
Andrew Connell
  • 4,939
  • 5
  • 30
  • 42

2 Answers2

2

Marvel's response got me thinking in the right direction... got it working and was a bit long to explain here so I blogged it here: http://www.andrewconnell.com/blog/archive/2012/05/02/isolating-integration-tests-with-ef4-x-code-first-amp-mstest.aspx

Andrew Connell
  • 4,939
  • 5
  • 30
  • 42
-1

Generally, these tests are highly integrated with Continuous Integration server with each single checking. So I think it would be better if you could order dbCreation test as the first test in your test settings, since it creates db with all necessary mappings. After, creating it at first test, the other tests can use Transactionscope in your base TestFixture class for the way you use it now and your integration tests work efficiently because you are not creating database with TestInitialize and TestCleanup.

public class BaseTestFixture
{

TransactionScope transactionScope;

    [TestInitialize]
    public void InitializeTests()
    {            

        if (IsTransactionScopeNeeded)
        {
            transactionScope = new TransactionScope();
        } 
    }

    [TestCleanup]
    public void CleanUp()
    {
        if (transactionScope != null)
            transactionScope.Dispose();

    }

}

public class DbContextTests : BaseTestFixture
{

    protected override bool IsTransactionScopeNeeded
    {
        get
        {
            return false;
        }
    }

    //This test should run first 
    [TestMethod]
    public void CreateDatabase_DatabaseNotExistedOrObselete_DatabaseCreated()
    {
    }
}
marvelTracker
  • 4,691
  • 3
  • 37
  • 49
  • 1
    This would require creating ordered tests... yes? I'm trying to avoid ordered tests as they are not recognized by the test runner we use. – Andrew Connell May 01 '12 at 10:52
  • I think in your build server you can execute DbContext test from giving a command rather using an ordered test list. Rest can be executed by using an ordered test list – marvelTracker May 01 '12 at 15:51
  • -1: _Ordered tests_ is an [anti-pattern](http://stackoverflow.com/a/333814/11808). – Christoffer Lette Mar 14 '13 at 09:21