Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSTest, MyClassInitialize, and instance variables

I wonder what the best practice is for initializing instance variables in a test class under MSTest. Let's say I have a test class where there is a lot of overhead to mocking and setting up supporting objects. I want to just do this once, instead of repeating the same code in each test. My thought was to use the MyClassInitialize method to initialize some global instance variables that all tests had access to. That way, I initialize the global instance variables once and they are just used by each test as they run.

Unfortunately, the MyClassInitialize method is static, so cannot initialize global instance variables. I thought about making the global instance variables static, but doesn't seem to be the right solution. I next thought about just putting the initialization code in a constructor of the test class itself, but something inside me keeps saying that MyClassInitialize is what I am supposed to be using. Another thought would be to use MyTestInitialize since that method is not static, but that would be creating the object over and over with each test. Is that appropriate?

Are there best practices for how to use variables across tests where those variables need only be initialized once before the tests run? Below is a contrived example of what I am talking about.

[TestClass()]
public class ProgramTest
{
    // this object requires extensive setup so would like to just do it once
    private SomeObjectThatIsUsedByAllTestsAndNeedsInitialization myObject;
    private TestContext testContextInstance;

    [ClassInitialize()]
    public static void MyClassInitialize(TestContext testContext)
    {
        // initializing SomeObjectThatIsUsedByAllTestsAndNeedsInitialization clearly will
        // not work here because this method is static.
    }

    [TestMethod()]
    public void Test1()
    {
        // use SomeObjectThatIsUsedByAllTestsAndNeedsInitialization here
    }

    [TestMethod()]
    public void Test2()
    {
        // use SomeObjectThatIsUsedByAllTestsAndNeedsInitialization here
    }

    [TestMethod()]
    public void Test3()
    {
        // use SomeObjectThatIsUsedByAllTestsAndNeedsInitialization here
    }
}
like image 654
meyousikmann Avatar asked Mar 14 '12 19:03

meyousikmann


People also ask

What is ClassInitialize attribute in MSTest?

The method decorated by [ClassInitialize] is called once before running the tests of the class. In some cases, you can write the code in the constructor of the class. The method decorated by [ClassCleanup] is called after all tests from all classes are executed.

What is ClassInitialize?

ClassInitialize runs only on the initialization of the class where the attribute is declared. In other words it won't run for every class. Just for the class that contains the ClassInitialize method. If you want a method that will run once before all tests or classes' initialization use the AssemblyInitialize .

What is MSTest used for?

MSTest is a number-one open-source test framework that is shipped along with the Visual Studio IDE. It is also referred to as the Unit Testing Framework. However, MSTest is the same within the developer community. MSTest is used to run tests.

Does TestInitialize run for each test?

TestInitialize and TestCleanup are ran before and after each test, this is to ensure that no tests are coupled. If you want to run methods before and after ALL tests, decorate relevant methods with the ClassInitialize and ClassCleanup attributes. Save this answer.


2 Answers

Use [TestInitialize] and [TestCleanup] whenever possible. A unit test should be fast and isolated, so the cleanest way is to initialise and cleanup for each test. This ensures the results of a test are not influenced by another test. When the initialization of a test takes long, you probably didn't wite a unit test but an integration test.

The exception is integration tests that go to the database or another resource, it is possible that you want to execute an operation once, and then verify the result with multiple assertions (TestMethods). I used to have a specific generic class with a context type that is only initialized once per class. But now I think this is overkill, and just put the dependencies and results in private static variables.

like image 137
Tim Cools Avatar answered Sep 28 '22 08:09

Tim Cools


What's your problem with static?

If your ObjectThatIsUsedByAllTests can really genuinely 100% be shared between all your tests then make it static and use ClassInitialize - that's what it's for.

If it isn't then you have to initialize it per test which is what TestInitialize is for.

like image 22
Nigel Harper Avatar answered Sep 28 '22 09:09

Nigel Harper