Parameterized Tests For Selenium Testing
Tags: csharp, selenium, testing, xunit
Published: 2021-05-19 10:34:41

When a developer comes up with unit tests, there are multiple ways through which they try to optimize the test code. Reduction of code size by reusing the existing code is one way of achieving the same. While working with frameworks like xUnit, Test fixtures can be streamlined by devising data-driven tests or xUnit parameterized tests, thereby taking advantage of code reusability.

Like other popular test frameworks in C#, the [xUnit framework](https://www.lambdatest.com/blog/xunit-testing-tutorial/?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-19052021&utm_term=Himanshu) also supports parameterized and non-parameterized tests for Selenium testing. The Fact attribute in xUnit denotes a test method that does not take any input arguments. On the other hand, the Theory attribute specifies a test that can take input parameters, and the method can be tested against different input combinations.

You can refer to our earlier blogs on the xUnit framework if you want to get started with [automated browser testing](https://www.lambdatest.com/selenium-automation?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-19052021&utm_term=Himanshu) using that framework. Parameterized tests in xUnit can be created using Theory tests, which can be used along with attributes like InlineData, ClassData, and MemberData to pass data into the test methods.

For a demonstration of parameterized tests in xUnit for cross browser testing, we use the Cloud Selenium Grid on LambdaTest. [LambdaTest](https://www.lambdatest.com/?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-19052021&utm_term=Himanshu) is a cloud-based cross browser testing platform using which automated browser tests can be performed on 2000+ real browsers and operating systems online. A valid combination of user-name and access-key is required to access LambdaTest’s Selenium Grid, which can be obtained from the [LambdaTest Profile Page](https://accounts.lambdatest.com/profile).

Apart from scalability, the other advantage of cloud-based cross browser testing is that tests can be executed in parallel resulting in faster test execution and improved test coverage. Browser capabilities generated using the LambdaTest capabilities generator serve as the input arguments to the xUnit parameterized test methods.

In this ongoing xUnit tutorial, we have already seen [how to run the first script in xUnit](https://www.lambdatest.com/blog/running-first-xunit-script/?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-19052021&utm_term=Himanshu). In this tutorial we will see some of the ways to implement xUnit parameterized tests using the Theory attribute and other popular attributes that enable parameterization:

## Parameterized tests in xUnit with InlineData

The InlineData attribute is commonly used to supply data to a Theory attribute-based parameterized test in xUnit. Every instance of the InlineData attribute creates a separate occurrence of the test method. The type and order of the parameters in the InlineData attribute should match with the values that are passed to the constructor. Let’s look at the demonstration of the same in this xUnit tutorial.

### Demonstration – [InlineData] Attribute

For demonstrating the usage of the InlineData attribute on parallelized cross browser tests, we perform the following tests on different browser & OS combinations.

**Test Case 1** – LamdaTest To-Do App

1. Navigate to the To-Do app https://lambdatest.github.io/sample-todo-app/ using selected browsers.

2. Check the first two items.

3. Add a new item – Adding item to the list.

4. Click the Add button to add that new item to the list.

Browsers on which cross browser testing is performed are:

| Browser | Browser version | Platform/Operating System |
| --- | --- | --- |
| Chrome | 72.0 | Windows 10 |
| Microsoft Edge | 18.0 | Windows 10 |
| Firefox | 70.0 | Windows 10 |
| Safari | 12.0 | macOS Mojave |

**Test Case 2 & 3** – Google Search for LambdaTest (using a different browser and OS combinations)

1. Navigate to Google.com.
2. Search for LambdaTest.
3. Quit the browser window.

Both the test cases are the same, but the execution will be performed on different web browsers.

**Test Case 2**

| Browser | Browser version | Platform/Operating System |
| --- | --- | --- |
| Chrome | 72.0 | Windows 10 |
| Microsoft Edge | 18.0 | Windows 10 |
| Firefox | 70.0 | Windows 10 |

**Test Case 3**

| Browser | Browser version | Platform/Operating System |
| --- | --- | --- |
| Microsoft Edge | 18.0 | Windows 10 |
| Firefox | 70.0 | macOS High Sierra |
| Chrome | 72.0 | Windows 10 |
| Microsoft Edge | 12.0 | macOS Mojave |

The complete implementation is below:

```csharp
using Xunit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Interactions;
/* For using Remote Selenium WebDriver */
using OpenQA.Selenium.Remote;
 
[assembly: CollectionBehavior(MaxParallelThreads = 4)]
 
namespace ParallelLTSelenium
{
    public class GlobalVar
    {
        static int _globalValue;
        public static int GlobalValue
        {
            get
            {
                return _globalValue;
            }
            set
            {
                _globalValue = value;
            }
        }
 
        public static String username = "user-name";
        public static String accesskey = "access-key";
        public static String gridURL = "@hub.lambdatest.com/wd/hub";
        public static DesiredCapabilities capabilities = new DesiredCapabilities();
        public static IWebDriver driver1;
    }
 
    public class ParallelLTTests : IDisposable
    {
        public ParallelLTTests()
        {
            GlobalVar.capabilities.SetCapability("user", GlobalVar.username);
            GlobalVar.capabilities.SetCapability("accessKey", GlobalVar.accesskey);
        }
 
        public void Dispose()
        {
            // Closure handled in each test case
        }
    }
 
    public class UnitTest_1 : IClassFixture<ParallelLTTests>
    {
        [Theory]
        [InlineData("chrome", "72.0", "Windows 10")]
        [InlineData("MicrosoftEdge", "18.0", "Windows 10")]
        [InlineData("Firefox", "70.0", "Windows 10")]
        [InlineData("Safari", "12.0", "macOS Mojave")]
 
        public void LT_ToDo_Test(String browser, String version, String os)
        {
            String itemName = "Yey, Let's add it to list";
            IWebDriver driver;
 
            GlobalVar.capabilities.SetCapability("browserName", browser);
            GlobalVar.capabilities.SetCapability("version", version);
            GlobalVar.capabilities.SetCapability("platform", os);
            GlobalVar.capabilities.SetCapability("build", "[xUnit - 1] LT ToDoApp using Xunit in Parallel on LambdaTest");
            GlobalVar.capabilities.SetCapability("name", "[xUnit - 1] - LT ToDoApp using Xunit in Parallel on LambdaTest");
 
            driver = new RemoteWebDriver(new Uri("https://" + GlobalVar.username + ":" + GlobalVar.accesskey + GlobalVar.gridURL), GlobalVar.capabilities, TimeSpan.FromSeconds(2000));
            driver.Url = "https://lambdatest.github.io/sample-todo-app/";
 
            Assert.Equal("Sample page - lambdatest.com", driver.Title);
            // Click on First Check box
            IWebElement firstCheckBox = driver.FindElement(By.Name("li1"));
            firstCheckBox.Click();
 
            // Click on Second Check box
            IWebElement secondCheckBox = driver.FindElement(By.Name("li2"));
            secondCheckBox.Click();
 
            // Enter Item name
            IWebElement textfield = driver.FindElement(By.Id("sampletodotext"));
            textfield.SendKeys(itemName);
 
            // Click on Add button
            IWebElement addButton = driver.FindElement(By.Id("addbutton"));
            addButton.Click();
 
            // Verified Added Item name
            IWebElement itemtext = driver.FindElement(By.XPath("/html/body/div/div/div/ul/li[6]/span"));
            String getText = itemtext.Text;
            Assert.True(itemName.Contains(getText));
 
            /* Perform wait to check the output */
            System.Threading.Thread.Sleep(2000);
 
            Console.WriteLine("LT_ToDo_Test Passed");
 
            driver.Close();
            driver.Quit();
        }
    }
    public class UnitTest_2 : IClassFixture<ParallelLTTests>
    {
        [Theory]
        [InlineData("chrome", "72.0", "Windows 10")]
        [InlineData("MicrosoftEdge", "18.0", "Windows 10")]
        [InlineData("Firefox", "70.0", "Windows 10")]
 
        public void Google_Test_1(String browser, String version, String os)
        {
            IWebDriver driver;
 
            GlobalVar.capabilities.SetCapability("browserName", browser);
            GlobalVar.capabilities.SetCapability("version", version);
            GlobalVar.capabilities.SetCapability("platform", os);
            GlobalVar.capabilities.SetCapability("build", "[xUnit - 2] - Google search (1) using XUnit in Parallel on LambdaTest");
            GlobalVar.capabilities.SetCapability("name", "[xUnit - 2] - Google search (1) using XUnit in Parallel on LambdaTest");
 
            driver = new RemoteWebDriver(new Uri("https://" + GlobalVar.username + ":" + GlobalVar.accesskey + GlobalVar.gridURL), GlobalVar.capabilities, TimeSpan.FromSeconds(2000));
            driver.Url = "https://www.google.com";
 
            System.Threading.Thread.Sleep(2000);
 
            IWebElement element = driver.FindElement(By.XPath("//*[@id='tsf']/div[2]/div[1]/div[1]/div/div[2]/input"));
 
            element.SendKeys("LambdaTest");
 
            /* Submit the Search */
            element.Submit();
 
            /* Perform wait to check the output */
            System.Threading.Thread.Sleep(2000);
 
            Console.WriteLine("Google_Test Passed");
 
            driver.Close();
            driver.Quit();
        }
    }
 
    public class UnitTest_3 : IClassFixture<ParallelLTTests>
    {
        [Theory]
        [InlineData("chrome", "72.0", "Windows 10")]
        [InlineData("MicrosoftEdge", "18.0", "Windows 10")]
        [InlineData("Firefox", "70.0", "macOS High Sierra")]
        [InlineData("Safari", "12.0", "macOS Mojave")]
 
        public void Google_Test_2(String browser, String version, String os)
        {
            IWebDriver driver;
 
            GlobalVar.capabilities.SetCapability("browserName", browser);
            GlobalVar.capabilities.SetCapability("version", version);
            GlobalVar.capabilities.SetCapability("platform", os);
            GlobalVar.capabilities.SetCapability("build", "[xUnit - 2] - Google Search (2) using XUnit in Parallel on LambdaTest");
            GlobalVar.capabilities.SetCapability("name", "[xUnit - 2] - Google Search (2) using XUnit in Parallel on LambdaTest");
 
            driver = new RemoteWebDriver(new Uri("https://" + GlobalVar.username + ":" + GlobalVar.accesskey + GlobalVar.gridURL), GlobalVar.capabilities, TimeSpan.FromSeconds(2000));
            driver.Url = "https://www.google.com";
 
            System.Threading.Thread.Sleep(2000);
            IWebElement element = driver.FindElement(By.XPath("//*[@id='tsf']/div[2]/div[1]/div[1]/div/div[2]/input"));
 
            element.SendKeys("LambdaTest");
 
            /* Submit the Search */
            element.Submit();
 
            /* Perform wait to check the output */
            System.Threading.Thread.Sleep(2000);
 
            Console.WriteLine("Google_Test Passed");
 
            driver.Close();
            driver.Quit();
        }
    }
}
```

**Code WalkThrough**

**Step 1 –** As the tests are executed in parallel, thread-based parallelism is achieved by setting ‘Max number of Parallel Threads to 4.’

```
[assembly: CollectionBehavior(MaxParallelThreads = 4)]
```

**Step 2 –** The combination of user-name and access-key are used to access the remote Selenium grid on LambdaTest.

```
String username = "user-name";
String accesskey = "access-key";
String gridURL = "@hub.lambdatest.com/wd/hub";
.......................................................................
```
 

**Step 3 –** The browser capabilities generated by the LambdaTest capabilities generator are passed to the remote Selenium WebDriver API.

```
GlobalVar.capabilities.SetCapability("browserName", browser);
GlobalVar.capabilities.SetCapability("version", version);
GlobalVar.capabilities.SetCapability("platform", os);
GlobalVar.capabilities.SetCapability("build", "[xUnit - 1] LT ToDoApp using Xunit in Parallel on LambdaTest");
GlobalVar.capabilities.SetCapability("name", "[xUnit - 1] - LT ToDoApp using Xunit in Parallel on LambdaTest");
 
.................................................................................
.................................................................................
.................................................................................
driver = new RemoteWebDriver(new Uri("https://user-name:access-key@hub.lambdatest.com/wd/hub"), capabilities, TimeSpan.FromSeconds(600));
```
 

**Step 4 –** The implementation under IDisposable [i.e., public void Dispose()] is empty as the resources held by the Selenium WebDriver for test execution are released after the corresponding test has completed execution.

```

public class ParallelLTTests : IDisposable
    {
        public ParallelLTTests()
        {
            GlobalVar.capabilities.SetCapability("user", GlobalVar.username);
            GlobalVar.capabilities.SetCapability("accessKey", GlobalVar.accesskey);
        }
 
        public void Dispose()
        {
            // Closure handled in each test case
        }
}
```
 

**Step 5 –** The browser + OS combinations that were generated for cross browser testing are used as parameters to the InlineData attribute. In turn, these values are passed to the constructor of InlineData, which then acts as arguments to the test method, i.e., LT\_ToDo\_Test for test case – 1.

For all the tests, a separate execution of InlineData creates a separate execution of the corresponding test method, i.e., for each test case, an iterative execution is carried out till the time all the input values as part of the InlineData attribute are exhausted.

```
public class UnitTest_1
{
	 [Theory]
       [InlineData("chrome", "72.0", "Windows 10")]
       [InlineData("MicrosoftEdge", "18.0", "Windows 10")]
       [InlineData("Firefox", "70.0", "Windows 10")]
       [InlineData("Safari", "12.0", "macOS Mojave")]
 
       public void LT_ToDo_Test(String browser, String version, String os)
       {
            String itemName = "Yey, Let's add it to list";
            IWebDriver driver;
 
            GlobalVar.capabilities.SetCapability("browserName", browser);
            ...................
	      ...................
 
            driver.Url = "https://lambdatest.github.io/sample-todo-app/";
```
 

The execution snapshot is as shown below:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image1-3-1024x357.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image3-1-1024x530.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image2-6-1024x490.png)

The InlineData should be used in scenarios when the method parameters are constants.

## Parameterized tests in xUnit with MemberData

Unlike the InlineData attribute that can be used to provide simple compile-time constants as parameters to the test method, the MemberData attribute has more flexibility.

It can be used to fetch data for the Theory attribute using a static method that is local to the test class, using a method from another class, or passing a complex object type.

For a demonstration of parameterization in xUnit using the MemberData attribute, we will load the browser + OS combinations from a method on a different class. In this xUnit tutorial, we will look at the demonstration of the same.

### Demonstration – [MemberData] Attribute

For demonstrating the usage of the MemberData attribute on parallelized cross browser tests, we perform the following tests on different browser & OS combinations.

**Test Case 1 –** LamdaTest To Do App

1. Navigate to the to-do app https://lambdatest.github.io/sample-todo-app/ using selected browsers.

2. Check the first two items.

3. Add a new item – Adding item to the list.

4. Click the Add button to add that new item to the list.

Browsers on which cross-browser testing is performed are:

| Browser | Browser version | Platform/Operating System |
| --- | --- | --- |
| Chrome | 72.0 | Windows 10 |
| Microsoft Edge | 18.0 | Windows 10 |
| Firefox | 70.0 | Windows 10 |
| Safari | 12.0 | macOS Mojave |

**Test Case 2 –** Google Search for LambdaTest (using a different browser and OS combinations)

1. Navigate to Google.com.
2. Search for LambdaTest.
3. Quit the browser window.

Browsers on which cross-browser testing is performed are:

| Browser | Browser version | Platform/Operating System |
| --- | --- | --- |
| Microsoft Edge | 18.0 | Windows 10 |
| Firefox | 70.0 | macOS High Sierra |
| Safari | 12.0 | macOS Mojave |

The complete implementation is below:

```csharp
using Xunit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Interactions;
/* For using Remote Selenium WebDriver */
using OpenQA.Selenium.Remote;
 
[assembly: CollectionBehavior(MaxParallelThreads = 4)]
 
/* Inputs taken from https://stackoverflow.com/questions/9110419/test-parameterization-in-xunit-net-similar-to-nunit */
 
namespace ParallelLTSelenium
{
    public class GlobalVar
    {
        static int _globalValue;
        public static int GlobalValue
        {
            get
            {
                return _globalValue;
            }
            set
            {
                _globalValue = value;
            }
        }
 
        public static String username = "user-name";
        public static String accesskey = "access-key";
        public static String gridURL = "@hub.lambdatest.com/wd/hub";
        public static DesiredCapabilities capabilities = new DesiredCapabilities();
        public static IWebDriver driver1;
    }
 
    public class ParallelLTTests : IDisposable
    {
        public ParallelLTTests()
        {
            GlobalVar.capabilities.SetCapability("user", GlobalVar.username);
            GlobalVar.capabilities.SetCapability("accessKey", GlobalVar.accesskey);
        }
 
        public void Dispose()
        {
            //Closure handled in each test case
        }
    }
    public static class LT_ToDo_Test_DataSource
    {
        private static readonly List<object[]> _data = new List<object[]>
        {
            new object[] {"chrome", "72.0", "Windows 10"},
            new object[] {"MicrosoftEdge", "18.0", "Windows 10"},
            new object[] {"Firefox", "70.0", "Windows 10"},
            new object[] {"Safari", "12.0", "macOS Mojave"}
        };
 
        private static readonly List<object[]> _data_2 = new List<object[]>
        {
            new object[] {"chrome", "72.0", "Windows 10"},
            new object[] {"Firefox", "70.0", "Windows 10"},
            new object[] {"Safari", "12.0", "macOS Mojave"},
        };
 
        public static IEnumerable<object[]> CB_Data
        {
            get
            { 
                return _data;
            }
        }
 
        public static IEnumerable<object[]> CB_Data_2
        {
            get
            {
                return _data_2;
            }
        }
    }
 
    public class UnitTest_1 : IClassFixture<ParallelLTTests>
    {
        [Theory]
        [MemberData("CB_Data", MemberType = typeof(LT_ToDo_Test_DataSource))]
        public void LT_ToDo_DataSource_Test(String browser, String version, String os)
        {
            String itemName = "Yey, Let's add it to list";
            IWebDriver driver;
 
            GlobalVar.capabilities.SetCapability("browserName", browser);
            GlobalVar.capabilities.SetCapability("version", version);
            GlobalVar.capabilities.SetCapability("platform", os);
            GlobalVar.capabilities.SetCapability("build", "[xUnit - 1] LT ToDoApp using Xunit in Parallel on LambdaTest");
            GlobalVar.capabilities.SetCapability("name", "[xUnit - 1] - LT ToDoApp using Xunit in Parallel on LambdaTest");
 
            driver = new RemoteWebDriver(new Uri("https://" + GlobalVar.username + ":" + GlobalVar.accesskey + GlobalVar.gridURL), GlobalVar.capabilities, TimeSpan.FromSeconds(2000));
            driver.Url = "https://lambdatest.github.io/sample-todo-app/";
 
            Assert.Equal("Sample page - lambdatest.com", driver.Title);
            // Click on First Check box
            IWebElement firstCheckBox = driver.FindElement(By.Name("li1"));
            firstCheckBox.Click();
 
            // Click on Second Check box
            IWebElement secondCheckBox = driver.FindElement(By.Name("li2"));
            secondCheckBox.Click();
 
            // Enter Item name
            IWebElement textfield = driver.FindElement(By.Id("sampletodotext"));
            textfield.SendKeys(itemName);
 
            // Click on Add button
            IWebElement addButton = driver.FindElement(By.Id("addbutton"));
            addButton.Click();
 
            // Verified Added Item name
            IWebElement itemtext = driver.FindElement(By.XPath("/html/body/div/div/div/ul/li[6]/span"));
            String getText = itemtext.Text;
            Assert.True(itemName.Contains(getText));
 
            /* Perform wait to check the output */
            System.Threading.Thread.Sleep(2000);
 
            Console.WriteLine("LT_ToDo_Test Passed");
 
            driver.Close();
            driver.Quit();
        }
    }
 
    public class UnitTest_2 : IClassFixture<ParallelLTTests>
    {
        [Theory]
        [MemberData("CB_Data_2", MemberType = typeof(LT_ToDo_Test_DataSource))]
 
        public void LT_ToDo_DataSource_Test_2(String browser, String version, String os)
        {
            IWebDriver driver;
 
            GlobalVar.capabilities.SetCapability("browserName", browser);
            GlobalVar.capabilities.SetCapability("version", version);
            GlobalVar.capabilities.SetCapability("platform", os);
            GlobalVar.capabilities.SetCapability("build", "[xUnit - 2] - Google search (1) using XUnit in Parallel on LambdaTest");
            GlobalVar.capabilities.SetCapability("name", "[xUnit - 2] - Google search (1) using XUnit in Parallel on LambdaTest");
 
            driver = new RemoteWebDriver(new Uri("https://" + GlobalVar.username + ":" + GlobalVar.accesskey + GlobalVar.gridURL), GlobalVar.capabilities, TimeSpan.FromSeconds(2000));
            driver.Url = "https://www.google.com";
 
            System.Threading.Thread.Sleep(2000);
 
            IWebElement element = driver.FindElement(By.XPath("//*[@id='tsf']/div[2]/div[1]/div[1]/div/div[2]/input"));
 
            element.SendKeys("LambdaTest");
 
            /* Submit the Search */
            element.Submit();
 
            /* Perform wait to check the output */
            System.Threading.Thread.Sleep(2000);
 
            Console.WriteLine("Google_Test Passed");
 
            driver.Close();
            driver.Quit();
        }
    }
}
```

**Code WalkThrough**

**Steps 1-4 –** These steps remain the same as those mentioned in the Code WalkThrough of the example demonstrating the InlineData attribute. The implementation of the core logic related to the test cases remains the same. The major change is the addition of MemberData for parameterization.

**Step 5 –** The data is loaded from a property or method of some other type. For a scenario that involves cross browser testing, this approach works perfectly fine as the number of browser combinations can be added without much effort.

A CB\_Data property is added which returns an IEnumerable\<object[]\>. CB\_Data and CB\_Data\_2 properties of LT\_ToDo\_Test\_DataSource are used in the MemberData attribute for the two test cases.

```
public static class LT_ToDo_Test_DataSource
{
        private static readonly List<object[]> _data = new List<object[]>
        {
            new object[] {"chrome", "72.0", "Windows 10"},
            new object[] {"MicrosoftEdge", "18.0", "Windows 10"},
            new object[] {"Firefox", "70.0", "Windows 10"},
            new object[] {"Safari", "12.0", "macOS Mojave"}
        };
 
        ...................
	  ...................
 
        public static IEnumerable<object[]> CB_Data
        {
            get
            { 
                return _data;
            }
        }
 
        ...................
	  ...................
}
public class UnitTest_1 : IClassFixture<ParallelLTTests>
{
   [Theory]
   [MemberData("CB_Data", MemberType = typeof(LT_ToDo_Test_DataSource))]
   public void LT_ToDo_DataSource_Test(String browser, String version, String os)
{
   ...................
   ...................
}
```
 

Shown below is the execution snapshot:

![automation testing](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/automation-testing-1024x315.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image7-1-1024x525.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image4-5-1024x494.png)

## Parameterized tests in xUnit with ClassData

Like MemberData, ClassData is another attribute that is used to pass values to Theory that are not constants. For providing parameters via ClassData, a class has to be created that inherits from IEnumerable\<object[]\>. A private list of objects containing the browser + OS combinations is then passed to the Theory attribute.

A GetEnumerator method has to be created on the list Enumerator. Finally, the Class is passed to the ClassData attribute, where the data returned from the class populate the test parameters.

If any of these steps are missed out, the xUnit framework throws an error.

Let’s understand implementing the same in this xUnit tutorial.

### Demonstration – [ClassData] Attribute

For demonstrating the usage of the ClassData attribute on parallelized cross browser tests, the same set of tests demonstrating the usage of MemberData is used. You can refer to the test cases in the Demonstration – [MemberData] attribute section before looking into the below implementation.

 ```csharp
 using Xunit;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium.Interactions;
/* For using Remote Selenium WebDriver */
using OpenQA.Selenium.Remote;
 
[assembly: CollectionBehavior(MaxParallelThreads = 4)]
 
namespace ParallelLTSelenium
{
    public class GlobalVar
    {
        static int _globalValue;
        public static int GlobalValue
        {
            get
            {
                return _globalValue;
            }
            set
            {
                _globalValue = value;
            }
        }
 
        public static String username = "user-name";
        public static String accesskey = "access-key";
        public static String gridURL = "@hub.lambdatest.com/wd/hub";
        public static DesiredCapabilities capabilities = new DesiredCapabilities();
        public static IWebDriver driver1;
    }
 
    public class ParallelLTTests : IDisposable
    {
        public ParallelLTTests()
        {
            GlobalVar.capabilities.SetCapability("user", GlobalVar.username);
            GlobalVar.capabilities.SetCapability("accessKey", GlobalVar.accesskey);
        }
 
        public void Dispose()
        {
            //Closure handled in each test case
        }
    }
    public class LT_ToDo_Test_DataSource : IEnumerable<object[]>
    {
        private readonly List<object[]> _data = new List<object[]>
        {
            new object[] { "chrome", "72.0", "Windows 10" },
            new object[] { "MicrosoftEdge", "18.0", "Windows 10" },
            new object[] {"Firefox", "70.0", "Windows 10"},
            new object[] {"Safari", "12.0", "macOS Mojave"}
        };
 
        public IEnumerator<object[]> GetEnumerator()
        {
            return _data.GetEnumerator();
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
 
    public class LT_ToDo_Test_DataSource_2 : IEnumerable<object[]>
    {
        private readonly List<object[]> _data = new List<object[]>
        {
            new object[] { "chrome", "72.0", "Windows 10" },
            new object[] { "Firefox", "70.0", "Windows 10" },
            new object[] { "Safari", "12.0", "macOS Mojave" }
        };
 
        public IEnumerator<object[]> GetEnumerator()
        {
            return _data.GetEnumerator();
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
 
    public class UnitTest_1 : IClassFixture<ParallelLTTests>
    {
        [Theory, ClassData(typeof(LT_ToDo_Test_DataSource))]
        public void LT_ToDo_DataSource_Test(String browser, String version, String os)
        {
            String itemName = "Yey, Let's add it to list";
            IWebDriver driver;
 
            GlobalVar.capabilities.SetCapability("browserName", browser);
            GlobalVar.capabilities.SetCapability("version", version);
            GlobalVar.capabilities.SetCapability("platform", os);
            GlobalVar.capabilities.SetCapability("build", "[xUnit - 1] LT ToDoApp using Xunit in Parallel on LambdaTest");
            GlobalVar.capabilities.SetCapability("name", "[xUnit - 1] - LT ToDoApp using Xunit in Parallel on LambdaTest");
 
            driver = new RemoteWebDriver(new Uri("https://" + GlobalVar.username + ":" + GlobalVar.accesskey + GlobalVar.gridURL), GlobalVar.capabilities, TimeSpan.FromSeconds(2000));
            driver.Url = "https://lambdatest.github.io/sample-todo-app/";
 
            Assert.Equal("Sample page - lambdatest.com", driver.Title);
            // Click on First Check box
            IWebElement firstCheckBox = driver.FindElement(By.Name("li1"));
            firstCheckBox.Click();
 
            // Click on Second Check box
            IWebElement secondCheckBox = driver.FindElement(By.Name("li2"));
            secondCheckBox.Click();
 
            // Enter Item name
            IWebElement textfield = driver.FindElement(By.Id("sampletodotext"));
            textfield.SendKeys(itemName);
 
            // Click on Add button
            IWebElement addButton = driver.FindElement(By.Id("addbutton"));
            addButton.Click();
 
            // Verified Added Item name
            IWebElement itemtext = driver.FindElement(By.XPath("/html/body/div/div/div/ul/li[6]/span"));
            String getText = itemtext.Text;
            Assert.True(itemName.Contains(getText));
 
            /* Perform wait to check the output */
            System.Threading.Thread.Sleep(2000);
 
            Console.WriteLine("LT_ToDo_Test Passed");
 
            driver.Close();
            driver.Quit();
        }
    }
 
    public class UnitTest_2 : IClassFixture<ParallelLTTests>
    {
        [Theory, ClassData(typeof(LT_ToDo_Test_DataSource_2))]
        public void LT_ToDo_DataSource_Test_2(String browser, String version, String os)
        {
            IWebDriver driver;
 
            GlobalVar.capabilities.SetCapability("browserName", browser);
            GlobalVar.capabilities.SetCapability("version", version);
            GlobalVar.capabilities.SetCapability("platform", os);
            GlobalVar.capabilities.SetCapability("build", "[xUnit - 2] - Google search (1) using XUnit in Parallel on LambdaTest");
            GlobalVar.capabilities.SetCapability("name", "[xUnit - 2] - Google search (1) using XUnit in Parallel on LambdaTest");
 
            driver = new RemoteWebDriver(new Uri("https://" + GlobalVar.username + ":" + GlobalVar.accesskey + GlobalVar.gridURL), GlobalVar.capabilities, TimeSpan.FromSeconds(2000));
            driver.Url = "https://www.google.com";
 
            System.Threading.Thread.Sleep(2000);
 
            IWebElement element = driver.FindElement(By.XPath("//*[@id='tsf']/div[2]/div[1]/div[1]/div/div[2]/input"));
 
            element.SendKeys("LambdaTest");
 
            /* Submit the Search */
            element.Submit();
 
            /* Perform wait to check the output */
            System.Threading.Thread.Sleep(2000);
 
            Console.WriteLine("Google_Test Passed");
 
            driver.Close();
            driver.Quit();
        }
    }
}
```

**Code WalkThrough**

**Steps 1-4 –** These steps remain the same as those mentioned in the Code WalkThrough of the example demonstrating the InlineData attribute.

**Step 5 –** Class named LT\_ToDo\_Test\_DataSource is created which inherits the IEnumerable\<object[]\>. A private list of objects containing the browser combinations is created along with the implementation of the GetEnumerator method.

Classes LT\_ToDo\_Test\_DataSource & LT\_ToDo\_Test\_DataSource\_2 are used for providing parameters via ClassData for test case 1 & test case 2 respectively.

```
public class LT_ToDo_Test_DataSource : IEnumerable<object[]>
{
        private readonly List<object[]> _data = new List<object[]>
        {
            new object[] { "chrome", "72.0", "Windows 10" },
            new object[] { "MicrosoftEdge", "18.0", "Windows 10" },
            new object[] {"Firefox", "70.0", "Windows 10"},
            new object[] {"Safari", "12.0", "macOS Mojave"}
        };
 
        public IEnumerator<object[]> GetEnumerator()
        {
            return _data.GetEnumerator();
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
}
 
public class UnitTest_1 : IClassFixture<ParallelLTTests>
{
   [Theory, ClassData(typeof(LT_ToDo_Test_DataSource))]
   public void LT_ToDo_DataSource_Test(String browser, String version, String os)
  {
   	...................
   	...................
  }
}
```

The execution snapshot demonstrating parameterization in xUnit using ClassData attribute is below:

![demonstrating parameterization](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/demonstrating-parameterization-1024x319.png)

![parameterization](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/parameterization-1024x556.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image9-2-1024x492.png)

## Wrapping it up

In this [Selenium xUnit tutorial](https://www.lambdatest.com/blog/setting-selenium-webdriver-for-xunit/?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-19052021&utm_term=Himanshu), we have seen how test parameterization is widely used for testing that involves a large number of scenarios. It helps reduce clutter in the test code as there is less duplication and redundancy in the test code. For simple parameterized tests in the xUnit framework, the InlineData attribute is ideal, but for more complex scenarios, ClassData and MemberData are more suitable.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image6-1.jpg)

These attributes are very handy when performing exhaustive cross browser tests as most of the tests will involve numerous combinations of web browsers and platforms. The advantages of parameterization in xUnit can be multiplied if the automated browser tests are performed on cloud based cross browser testing platforms like LamdaTest as tests can be parallelized.