Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple TestInitialize attributes in MSTEST

Using MSTEST in VS2012.3 .NET4.5 and R# for the test runner.

The code below works in the order 1,2,3,4.

However I'm concerned that it may not always execute in this order as multiple TestInitialize attributes are not supported MSDN

Question: Is this allowed, and do the docs just mean that multiple TestInitialize attributes are not allowed in the same class?

I would like to keep this structure as have many integration tests inheriting off TransactedTestBase, yet requiring different SQL scripts to setup.

Same behaviour was found here

[TestClass]
public class DelegationTest : TransactedTestBase
{
    [TestInitialize]
    public void Setup()
    {
        Console.WriteLine("2 Setup");
        //var script = "INSERT INTO blah...";
        //var sqlConnect = new SqlConnection(dbConnection.ConnectionString);
        //sqlConnect.Open();
        //var server = new Server(sqlConnect);
        //var database = server.Databases[sqlConnect.Database];
        //database.ExecuteNonQuery(script);
    }

    [TestMethod]
    public void TestMethod1()
    {
        Console.WriteLine("3 Test Method");
    }
}

[TestClass]
public class TransactedTestBase
{
    //protected userEntities userEntities;
    //private TransactionScope scope;
    //public static SqlDatabase dbConnection;

    //private const bool ShouldWriteToDB = true;
    //private const bool ShouldWriteToDB = false;

    [TestInitialize()]
    public virtual void TestStart()
    {
        Console.WriteLine("1 TestStart");
        //if (ShouldWriteToDB)
        //{
        //    dbConnection = EnterpriseLibraryContainer.Current.GetInstance<SqlDatabase>("DBConnect");
        //    return;
        //}

        //scope = new TransactionScope(TransactionScopeOption.RequiresNew);
        //user = new userEntities();
        //dbConnection = EnterpriseLibraryContainer.Current.GetInstance<SqlDatabase>("DBConnect");
    }

    [TestCleanup()]
    public virtual void TestEnd()
    {
        Console.WriteLine("4 TestEnd");
        //if (ShouldWriteToDB) return;

        //scope.Dispose();
    }
}
like image 414
Dave Mateer Avatar asked Aug 29 '13 12:08

Dave Mateer


3 Answers

I believe the docs are referring to using the TestInitializeAttribute multiple times on the same method. This is controlled by the AttributeUsage(AllowMultiple=false). FWIW, I have a medium size test suite (~200 tests) predicated on the code you've shown working as you are expecting: TestStart is called before Setup.

There are issues with making the TestInitialize method virtual and overriding it (see here) and inheritance of ClassInitialize methods (MsTest ClassInitialize and Inheritance).

like image 130
Mike Zboray Avatar answered Sep 23 '22 05:09

Mike Zboray


I believe you misread the MSDN article. They state:

This attribute can be specified on a method. Only one instance of this attribute may be applied to a method.

Which means that you can not have code like this:

[TestInitialize]
[TestInitialize]
public void MyIntilialzer(){}

It does not mean you can't have multiple initializers, even in the same class.

I'm not sure about MSTest, but in NUnit its well defined that in the situation you describe, the initializers will be ran in the right order, from base class up. And if you have few initializers in the same class, the order is not guaranteed.

I would assume this is true for MSTest as well (but I don't have reference point).

like image 23
Sunny Milenov Avatar answered Sep 26 '22 05:09

Sunny Milenov


Be aware that the executing order depends on test runner. Visual Studio test runner and R# test runner might behave differently. Now I believe they have the same behavior, but still it is up to R# how it will behave.

I remember that one of R# old version has a bug and TestInitialize method from subclass was executed earlier then TestInitialize method in base class. Of course, it was fixed quickly :)

like image 30
Alexander Andronov Avatar answered Sep 24 '22 05:09

Alexander Andronov