NUnit pass data from OneTimeSetUp to all tests in that fixture

2.5k Views Asked by At

In NUnit, I am attempting to initialize a variable during the test fixture's OneTimeSetUp and reference that variable in all test cases under that fixture.

The OneTimeSetUpAttribute is applied to a function in a file called Initializer.cs, where I initialize a new instance of a Selenium IWebDriver named driver and apply some common configuration options. My test cases are defined in TestCases.cs in the same namespace and directory as Initializer.cs. Is it possible to somehow pass the driver variable to the test cases defined in TestCases.cs? If not, then how should I address initializing a new instance of IWebDriver on each new test run without having to initialize it during the SetUp of each test case file I add? See the code below.

I am using Visual Studio Test Explorer to execute the tests.

Initializer.cs

namespace AutomatedTests
{
    [SetUpFixture]
    public class Initializer
    {
        IWebDriver driver = null;

        [OneTimeSetUp]
        public void Before()
        {
            ChromeOptions options = new ChromeOptions();
            // some initial browser configuration here

            driver = new ChromeDriver(".");
        }

        [OneTimeTearDown]
        public void After()
        {
            driver.Close();
        }
    }
}

TestCases.cs

namespace AutoamtedTests
{
    public class TestCases
    {
        [Test]
        public void AutomatedTest()
        {
            // is it possible to reference 'driver' here?
        }
    }
}
3

There are 3 best solutions below

4
CEH On BEST ANSWER

You'll need to use [SetUp] and [TearDown] attributes to accomplish this -- place your [SetUp] and [TearDown] methods in your Initializer class, above the Before() and After() methods respectively. Then, in your TestCases class, inherit Initializer so that you can access the driver class variable you declare & initialize there. Here's an example:

public class Initializer
{
    IWebDriver driver = null;

    [SetUp]
    public void Before()
    {
        ChromeOptions options = new ChromeOptions();
        // some initial browser configuration here

        driver = new ChromeDriver(".");
    }

    [TearDown]
    public void After()
    {
        driver.Close();
    }
}

Then, TestCases.cs:

public class TestCases : Initializer // inherit initializer here
{
    [Test] // each time you run this test, [SetUp] runs first
    public void AutomatedTest()
    {
        driver.FindElement(); // driver class variable inherited from Initializer.cs

        // you can use driver to initialize PageObjects too
        var myPageObject = new MyPageObject(driver); 
        myPageObject.DoSomething();

    } // each time this test is completed, [TearDown] runs
}

This easily gives us a way to utilize the PageObject model, too, because you can initialize PageObjects on the test-case level.

4
Glenn van Acker On

Setup is meant to be executed once before each test, OneTimeSetup, this is executed before all the tests are run. https://github.com/nunit/docs/wiki/SetUp-and-TearDown

This way, you have a single method. Or you could create an initialization method, and run that in the beginning of each test.

Also, since the setup happens in the initializer, you should probably let your testcases inherit from that initializer. You also need a default constructor in your initializer. https://github.com/nunit/docs/wiki/SetUpFixture-Attribute

Another option, besides the inheritance, would be to make the driver property static. Then you can just call it like

var _driver = Initializer.driver;
0
Charlie On

There is not (and should not be) any connection between the SetUpFixture and the TestFixture it governs. As a result, there's no way to get the driver from the SetUpFixture except through a static property which is just asking for trouble!

In the case of a single fixture, the simplest thing to do is to create the driver in a OneTimeSetUp method within the fixture itself. In the case of multiple fixtures, you can repeat the same code or put it in a base class shared by all the fixtures. You will end up with one driver per fixture, which seems to be a good pattern for many web applications.

Note that you cannot share a fixture among tests that run in parallel. For parallel execution of test cases, you would have to initialize the driver in a SetUp method, so that each ase got it's own driver. The pattern I'm suggesting gives you a separate driver per fixture, so the fixtures can run in parallel while the test cases in each fixture should only run sequentially and should initialize the state of the driver as needed.