How to write Nunit Parameterized Test
By Gurudatt S A, Community Contributor - February 18, 2025
NUnit, a popular C# test framework, supports parameterized tests to eliminate code duplication and improve efficiency. Instead of writing separate test cases for different inputs, parameterization allows running a single test with multiple data sets.
This is especially useful in cross-browser testing, where the same test runs across various browser configurations.
This guide explores NUnit parameterized tests, their benefits, and how to implement them effectively.
- What Is Parameterization in NUnit?
- Importance of Parameterization In NUnit
- How to write Nunit Parameterized Test
- Parameterization techniques in NUnit
What Is Parameterization in NUnit?
NUnit is a widely used C# testing framework known for its compatibility with Selenium, making it a preferred choice for cross-browser testing.
Since version 2.5, NUnit has supported parameterized tests, allowing test methods to accept input values dynamically. This eliminates the need for redundant test cases by enabling a single test to run with multiple data sets.
NUnit provides various attributes to define test parameters, some allow inline argument specification, while others retrieve data from separate methods or fields, ensuring flexibility and reusability in test execution.
Importance of Parameterization In NUnit
Below are the key reasons why Parameterization in NUnit is important:
- Eliminates Code Duplication: A single test method can run with multiple inputs, reducing redundant test cases.
- Enhances Test Coverage: Ensures the application behaves correctly with various input values.
- Improves Maintainability: Changes in logic need to be updated only once, simplifying test management.
- Optimizes Test Execution: Running parameterized tests is faster than executing separate test cases for each input.
- Supports Cross-Browser Testing: Enables testing across different browsers and configurations efficiently.
How to write Nunit Parameterized Test
Parameterized tests in NUnit allow running the same test logic with different inputs, reducing redundancy and improving test efficiency.
Instead of writing multiple test methods for various input values, parameterized tests help execute a single test method with multiple data sets. NUnit provides multiple techniques to pass parameters to test methods, ensuring flexibility and ease of use.
Parameterization techniques in NUnit
There are Four ways to group the parameter and can be passed to the test in Nunit
- Inline – As Test Case Attribute
- Inline – As Random Attribute, Range Attribute, Values Attribute
- Separate – TestCaseSource Attribute
- Separate – ValueSource Attribute
Inline – As Test Case Attribute
In this technique, Nunit uses the TestCase attribute to pass the various data sets at Test level. This technique is helpful when we want to repeat complete test for various data sets. For the examples we’ll be using BrowserStack’s demo application
Attribute syntax is
[TestCase(“input1”, “input2”)]
For example,
using NUnit.Framework; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using System.IO; using System; using OpenQA.Selenium.Support.UI; namespace NunitSeleniumDemo { public class Tests { private IWebDriver driver; [SetUp] public void Setup() { String path = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\..\\..\\")); driver = new ChromeDriver(path + "\\drivers"); driver.Manage().Window.Maximize(); driver.Url = "https://bstackdemo.com/"; } [TestCase("OnePlus", "6 Product(s) found.")] [TestCase("Google", "3 Product(s) found.")] public void NunitSeleniumTest(String model, String message) { DefaultWait<IWebDriver> fluentWait = new DefaultWait<IWebDriver>(driver); fluentWait.Timeout = TimeSpan.FromSeconds(5); fluentWait.PollingInterval = TimeSpan.FromMilliseconds(250); fluentWait.Until(driver => driver.Title == "StackDemo"); driver.FindElement(By.XPath($"//*[@class='checkmark' and contains(text(),'{model}')]")).Click(); driver.Manage().Timeouts().ImplicitWait = (TimeSpan.FromSeconds(6)); String searchResults = driver.FindElement(By.XPath("//*[@class='products-found']//span")).Text; Assert.AreEqual(searchResults, $"{message}"); driver.FindElement(By.XPath($"//*[@class='checkmark' and contains(text(),'{model}')]")).Click(); } [TearDown] public void tearDown() { driver.Close(); driver.Quit(); } } }
In this example, reusing the same test for validating the search result after clicking a specific phone model.
As observed, first declaring the Attribute with the values you need to pass at test level
[TestCase("OnePlus", "6 Product(s) found.")] [TestCase("Google", "3 Product(s) found.")]
We receive these values as input parameters for our test method when Nunit runs, hence we declare two parameters for our test method
public void NunitSeleniumTest(String model, String message)
And now you can use these parameters in our code where the code clicks on the model and verifies the message
driver.FindElement(By.XPath($"//*[@class='checkmark' and contains(text(),'{model}')]")).Click(); driver.Manage().Timeouts().ImplicitWait = (TimeSpan.FromSeconds(6)); String searchResults = driver.FindElement(By.XPath("//*[@class='products-found']//span")).Text; Assert.AreEqual(searchResults, $"{message}"); driver.FindElement(By.XPath($"//*[@class='checkmark' and contains(text(),'{model}')]")).Click();
In this way, you can reuse our test for various datasets.
Inline Parameterization Using Random, Range, and Values Attributes
NUnit provides additional inline parameterization techniques—Random, Range, and Values attributes—to supply test methods with different sets of input data. These attributes eliminate the need for hardcoding multiple test cases, making test scripts more concise and scalable
Range Attribute
In this technique, Nunit allows two array parameters, which can be passed to the test method.
First parameter is the Values and the Second is the Range. Test repeats for all the Values provided for the range provided.
This can be used when you want to test various ranges for a given Value.
In the below example, the value is a selector, and the quantity is the range. With the given selector, test adds the Phone to the cart and validates the cart with the quantity.
using NUnit.Framework; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using System.IO; using System; using OpenQA.Selenium.Support.UI; namespace NunitSeleniumDemo { public class InlineDemo { private IWebDriver driver; [OneTimeSetUp] public void Setup() { String path = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\..\\..\\")); driver = new ChromeDriver(path + "\\drivers"); driver.Manage().Window.Maximize(); driver.Url = "https://bstackdemo.com/"; } [Test] public void checkQuantity([Values(".shelf-container")] String selector, [Range(2,3,1)] int value) { DefaultWait<IWebDriver> fluentWait = new DefaultWait<IWebDriver>(driver); fluentWait.Timeout = TimeSpan.FromSeconds(5); fluentWait.PollingInterval = TimeSpan.FromMilliseconds(250); fluentWait.IgnoreExceptionTypes(typeof(FormatException)); fluentWait.Until(driver => driver.Title == "StackDemo"); driver.FindElement(By.CssSelector($"{selector} .shelf-item:nth-of-type({value}) .shelf-item__buy-btn")).Click(); driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(120); fluentWait.Until(driver => Int32.Parse(driver.FindElement(By.CssSelector(".float-cart__header .bag__quantity")).Text) == (value - 1)); int cartQty = Int32.Parse( driver.FindElement(By.CssSelector(".float-cart__header .bag__quantity")).Text); Assert.AreEqual(cartQty, (value-1)); } [OneTimeTearDown] public void tearDown() { driver.Close(); driver.Quit(); } } }
Values Attribute
In this technique, Nunit allows two Values array parameters to be passed to the test. For every first value parameter, the Values in the Second parameter will be repeated.
Executing the below example
[Test] public void inlineValueTest([Values(1,2)] int value1, [Values(2, 3)] int value2) { Console.WriteLine("Value 1 is : " + value2); Console.WriteLine("Value 2 is : " + value2); }
The tests will be divided into
Random Attribute
In this technique, the Nunit allows you to pass Random Attribute Array with 1 to 3 parameters
Syntax:
Random(int count) Random(int minNumber, int MaxNumber, int count)
In the below example, we are specifying the Random number to be in range from 0 to 10 and repeat the test for every value 3 times
Executing the below example
[Test] public void inlineValueTest([Values(1,2)] int value1, [Random(0,10, 3)] int value2) { Console.WriteLine("Value 1 is : " + value2); Console.WriteLine("Value 2 is : " + value2); }
Nunit generates test with below combinations
Separate – TestCaseSource Attribute
In this technique, Nunit allows passing the data from different sources using Attribute [TestCaseSource]. This will allow us to keep the test data away from the test and can be used to read the data from External sources like a JSON file or Database.
[TestCaseSource(nameof(UserData))] public void testReadingFromDataSource(String userName, String password) { Console.WriteLine("Value 1 is : " + userName); Console.WriteLine("Value 2 is : " + password); } static object[] UserData = { new object[] { "username1", "passsword1" }, new object[] { "username2", "passsword2" } };
As we can see our test data is coming from a method called UserData which returns an array of objects. Nunit will run the test for every returning object array
Separate – ValueSource Attribute
In this technique, Nunit allows us to pass named data source at test method parameter level using attribute [ValueSource].
[Test] public void testReadingFromDataSource([ValueSource("UserData")] Object[] userObject) { Console.WriteLine("userName is : " + userObject[0]); Console.WriteLine("password is : " + userObject[1]); } static object[] UserData = { new object[] { "username1", "passsword1" }, new object[] { "username2", "passsword2" } };
As observed, the userData object now is applied to the test method’s parameter. Nunit will generate tests like below
Integrating NUnit Selenium Tests with BrowserStack
Running NUnit parameterized tests on BrowserStack’s cloud infrastructure enables seamless cross-browser and cross-device validation, ensuring robust test coverage.
- Real-Device Cloud: Test across real mobile and desktop devices to simulate real-world user conditions.
- Parallel Test Execution: Scale NUnit tests effortlessly by running them in parallel across multiple environments.
- Zero Infrastructure Hassle: Eliminate the need for setting up and maintaining in-house test environments.
- Detailed Debugging Tools: Capture screenshots, logs, and video recordings to analyze test failures effectively.
Read More: Detailed documentation on Integration between BrowserStack, NUnit & Selenium.
Conclusion
Parameterization is a powerful way of implementing our tests in a flexible way and can be reused for various data sets if designed properly. This will reduce the repetitive tests and also allows us to Maintain the tests keeping test data tidy. With TestCaseSource we can easily keep the test data outside the test which will make the test reusable against different test environments where test data might change.