Best XUnit Parameterized Tests Tutorial: Selenium Testing
Himanshu Sheth
Posted On: March 18, 2021
295919 Views
10 Min Read
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 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 using that framework. xUnit Parameterized tests 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 xUnit parameterized tests for cross browser testing, we use the Cloud Selenium Grid on LambdaTest. LambdaTest 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.
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 tests methods.
In this ongoing xUnit tutorial, we have already seen how to run the first script in xUnit. 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:
xUnit Parameterized tests with InlineData
The InlineData attribute is commonly used to supply data to a Theory attribute-based xUnit parameterized test. 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.
Take this certification to master the fundamentals of Selenium automation testing with C# and prove your credibility as a tester.
Here’s a short glimpse of the Selenium C# 101 certification from LambdaTest:
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
- Navigate to the To-Do app https://lambdatest.github.io/sample-todo-app/ using selected browsers.
- Check the first two items.
- Add a new item – Adding item to the list.
- Click the Add button to add that new item to the list.
Browsers on which cross browser testing is performed are:
Test Case 2 & 3 – Google Search for LambdaTest (using a different browser and OS combinations)
- Navigate to Google.com.
- Search for LambdaTest.
- Quit the browser window.
Both the test cases are the same, but the execution will be performed on different web browsers.
Test Case 2
Test Case 3
The complete implementation is below:
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.’
1 |
[assembly: CollectionBehavior(MaxParallelThreads = 4)] |
Step 2 – The combination of user-name and access-key are used to access the remote Selenium grid on LambdaTest.
1 2 3 4 |
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.
1 2 3 4 5 6 7 8 9 10 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
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:
The InlineData should be used in scenarios when the method parameters are constants.
This xUnit Tutorial for beginners and professionals will help you learn how to use xUnit framework with Selenium C# for performing Selenium automation testing.
xUnit Parameterized tests 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
- Navigate to the to-do app https://lambdatest.github.io/sample-todo-app/ using selected browsers.
- Check the first two items.
- Add a new item – Adding item to the list.
- Click the Add button to add that new item to the list.
Browsers on which cross-browser testing is performed are:
Test Case 2 – Google Search for LambdaTest (using a different browser and OS combinations)
- Navigate to Google.com.
- Search for LambdaTest.
- Quit the browser window.
Browsers on which cross-browser testing is performed are:
The complete implementation is below:
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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:
xUnit Parameterized tests 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.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
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:
Note: Experience reliable automated testing with Selenium Testing Tool on a cloud grid of 3000+ browsers and operating systems.
Wrapping it up
In this Selenium xUnit tutorial, 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 xUnit parameterized tests, the InlineData attribute is ideal, but for more complex scenarios, ClassData and MemberData are more suitable.
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.
Got Questions? Drop them on LambdaTest Community. Visit now