Why ClassInitialize functions need to be static.

I'm working in C++.  I'm not sure I understand how the XXXInitialize/Clean attribute is supposed to work.
The ClassInitialize method is called before the class is created (the function need to be static).  The TestInitialize is called before each tests.  I need a way to Initialize/Cleanup class member.  When I tried to put this initilization in the class constructor, I discovered the constructor was called many time ( ).  The desctuctor is also never called, so I don't have a way to do clean up.
This mean (if I understand well), I'll have to use static variable (ouch!) inside my class if I want to initialize it.  Not very object like!
Maybe I'm missing a point here, but I don't see why the ClassInitialize cannot initialize a class   Maybe this whole thing is making sense for a Web service, but it certainly does not for a standard desktop application.  Maybe what I'm looking for is somewhere else

Thank you.

Stephane Guerin


Answer this question

Why ClassInitialize functions need to be static.

  • Samuelson Ido

    So I can fill in some information during the ClassInitialize in the TestContext.Properties collection.  However how can I retreive it later (during a test for example)

    Stephane Guerin

  • misteloe

    Ok, So we are back at square one. My original question (on top of this thread) remains: I need a way to Initialize/Cleanup class member. Right now I need to create static variable in the test class. I don't see that as a very good way to do something as trivial.

    Stephane Guerin


  • Eunsu

    Thank you very much!  As you mention, very different from NUnit but the important is we can achieve the same result.

    Stephane Guerin

  • balo

    What's happening is that the class is re-instantiated for each test that runs. This is the intended behavior, though it is different from some other test frameworks like NUnit. ClassInitialize is called before the first test in that class is run, and ClassCleanup is called after the last test in that class, but the class will be instantiated multiple times between the two if multiple tests are run. If you want to initialize values that will persist for all tests in that class, you'll need to either use static members or store the data in the TestContext object (with TestContext.Properties).
  • ssundan

    Thank for the link. It explains how it is working well.

    However, I don't see any benifit to this behavior. When we setup a series of tests in a single class, we usually need to setup members for them. I understand the tests run in separate thread (and it's fine with me). However, to have to rely on static variable in a OO world does not seem appropriate. Also if we need a more global setup, the AssemblyInitialize is availlable to fill in any static variable in the system. There is almost no difference between AssemblyInitialize and the ClassInitialize. Both of them is only usefull to fill global variable.

    Anyway, thanks for the help.


  • Bent

    Same in MC++. Note that the syntax for defining property there is significantly different.

    #include "stdafx.h"

    using namespace System;
    using namespace System::Text;
    using namespace System::Collections::Generic;
    using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
    using namespace System::IO;

    namespace Foo
    {
     [TestClass]
     public ref class UnitTest1
     {
     public:
      [ClassInitialize()]
      static void MyClassInitialize(TestContext^ testContext)
      {
       testContext->Properties["Foo"] = "Save this string";
      };
      

      [TestMethod]
      void TestMethod1()
      {
       Console::WriteLine(TestContext->Properties["Foo"]);
      };

      property TestContext^ TestContext
      {
       Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ get() { return m_context; }
       void set(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ testContext) { m_context = testContext; }
      };

      Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ m_context;

     };
    }



  • Reactive

    I tried this again with VSTS and it seem a new context is created each time a test is run. The first test that run receive the context with the property that was added (the "Foo" property in your example). All the test that run after that failled to find the property. If you take the example you provided me and add a second test, you'll see you don't have the "Foo" property available anymore.

    Stephane Guerin.

  • jhermiz

    Hi Jan,

    I don't know if you are still interested in the answer, but here it goes. Actually, TextContext properties are not intended to be written into, they were left like that to support something in the future, if needed. So yes, they are lost on every test.

    I hope this is clear.

    Guillermo Serrato

    VS Team Test



  • bill1000

    I'm having the same problem using TestContext properties. Is it a bug that the TestContext is reset between each test

    When I run the tests using TestDriven.Net it works as expected, but not when I use VSTS.

    What are the intended use of TestContext.Properties Can it be used to set values in ClassInitialize that are accessible to all tests In my experience this does not work as the Properties are lost after the first test. What is correct

    Regards,

    Jan Lonsetteig


  • Jeff Lundstrom

    Hi Stephane,

    It is by design that TestContext is lost at every test. You can read more about it here: http://blogs.msdn.com/nnaderi/archive/2007/02/17/explaining-execution-order.aspx

    So for your case, using a static variable is the right thing to do. Since the TestClass is instantiated for each test, the only way to keep TestContext would be to make it static, so you would have the same behavior there.

    Cheers,

    Guillermo Serrato

    VS Team Test



  • Rod Kimmel

    You can define a property in the test class that will let you access the TestContext object. It should look like this:



    private TestContext testContextInstance;

    public TestContext TestContext
    {
       get { return testContextInstance; }
       set { testContextInstance = value; }
    }

     



    Before each test runs, the property will automatically be set (as long as it has the correct name and type), so you can then access it through this.TestContext. The same object is used for each test in the class, so any changes you make in ClassInitialize (or in a test) will persist for the following tests.


  • Why ClassInitialize functions need to be static.