12

I have a base class ScriptBase which has a virtual function called MyTestInitialize(). When I call MyTestInitialize() from derived class, then the value of testContextInstance is null. Is there any solution for this? Please help as I am new to Automation Testing. Thanks in Advance

[CodedUITest]
public class ScriptsBase
{
    public ScriptsBase()
    {   
    }

    private static TestContext bingTestContext;

    public static TestContext BingTestContext
    {
        get { return ScriptsBase.bingTestContext; }
        set { ScriptsBase.bingTestContext = value;}
    }

    #region TestInitialize
    //Use TestInitialize to run code before running each test 
    [TestInitialize()]
    public virtual void MyTestInitialize()
    {
        Browser.CloseAllBrowsers();
        BingTestContext = testContextInstance;
    }
    #endregion

    #region TestCleanup
    //Use TestCleanup to run code after each test has run
    [TestCleanup()]
    public virtual void MyTestCleanup()
    {
        PPI.HomePage = new HomePageUI();
        Browser.CloseAllBrowsers();
    }
    #endregion

    #region TestContext
    /// <summary>
    ///Gets or sets the test context which provides
    ///information about and functionality for the current test run.
    ///</summary>
    public TestContext TestContext
    {
        get
        {
            return testContextInstance;
        }
        set
        {
            testContextInstance = value;
        }
    }
    private TestContext testContextInstance;
    #endregion
}

 public class DestinationMasterTestScripts : ScriptsBase
  {
       public DestinationMasterTestScripts()
       {      
       }

       [TestInitialize()]
       public override void MyTestInitialize()
       {
           Console.WriteLine("Initialize");
           base.MyTestInitialize();
       }
   }     
Nathan
  • 10,593
  • 10
  • 63
  • 87
user3012888
  • 123
  • 1
  • 2
  • 5
  • 1
    Were you able to find any solution to your problem? However, when I tried with your code, I was able to get the TestContext object in base class as well. – digitguy Sep 21 '14 at 14:23

5 Answers5

7

Try creating a ClassInitialize method:

    private static TestContext bingTestContext

    [ClassInitialize]
    public static void ClassInit(TestContext con)
    {
      bingTestContext = con;
    }
Jens Kloster
  • 11,099
  • 5
  • 40
  • 54
  • 1
    Does this not interfere with the outputs of individual tests if you do this? – Nathan Jan 29 '14 at 22:27
  • I dont see how it could. But im not sure. This way is the only one (that I know how) if you want to use the `TestContext` – Jens Kloster Jan 30 '14 at 07:24
  • 2
    I did a little testing (MsTest, Visual Studio 2012), and with a "normal" TestContext property, MsTest assigns a *different* instance of TestContext per *test method*. With the `ClassInitialize` approach given here, you will have *one* `TestContext` instance shared among *all* test methods in the class. This means your unit tests are no longer isolated from each other if they store anything in the test context, or write to the test context via its `WriteLine` method. – Nathan Jan 30 '14 at 17:41
  • To be fair - the original poster also had a static TestContext instance which probably would have suffered from the same lack of test method isolation even if it worked - unless `[CodedUiTest]` tests behave differently than `[TestClass]` tests - I only checked against `[TestClass]` tests. – Nathan Jan 30 '14 at 17:49
  • @Nathan has a excellent point, the same symptoms are mentioned [here](http://stackoverflow.com/questions/24249133/understanding-the-mstest-testcontext), I think the take away from this is to BE VERY CAREFUL with this answer, it will work in some contexts, not others. – David Rogers Jan 18 '17 at 18:29
  • Why not make this an [AssemblyInitialize] so test classes running in parallel don't overwrite the shared context? – Luke Schoen Jan 08 '20 at 20:04
  • Also see [Unit Test Transactions in Visual Studio Load Tests](https://www.markschabacker.com/blog/2015/04/27/unit-tests-as-load-tests), which wraps the timer in an IDisposable and a using statement. – Charlesdwm Mar 02 '21 at 00:10
5

Another option is to declare the TestContext as abstract in your base class

public abstract TestContext TestContext { get; set; }

And override it in your most derived concrete class(es)

public override TestContext TestContext { get; set; }
Nathan
  • 10,593
  • 10
  • 63
  • 87
1

Not sure if something has changed in the 6 years since this question was posted, but this works for me almost as-is. Add [TestClass] to the derived class and the TestContext gets set up just fine. There's also no need for BingTestContext at all. Just use this.TestContext from derived classes.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

public class ScriptsBase
{
    public static TestContext BingTestContext { get; set; }

    public TestContext TestContext { get; set; }

    [TestInitialize]
    public virtual void MyTestInitialize()
    {
        BingTestContext = this.TestContext;
    }

    [TestCleanup]
    public virtual void MyTestCleanup()
    {
    }
}

[TestClass]
public class DestinationMasterTestScripts : ScriptsBase
{
    [TestInitialize]
    public override void MyTestInitialize()
    {
        base.MyTestInitialize();
    }

    [TestMethod]
    public void Foo()
    {
        Console.WriteLine(this.TestContext);
    }
}
Luke Schoen
  • 674
  • 6
  • 23
0

See if this helps, I find it working when I set base class TestContext with derived class one.

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

private TestContext testContextInstance;
Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
-1

You should use equal classes for Assert and TestContext like:

using Assert = NUnit.Framework.Assert;

using TestContext = NUnit.Framework.TestContext;
TalkLittle
  • 8,866
  • 6
  • 54
  • 51
Dmitry
  • 1