Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

NUnit provides methods to run multiple test cases, saving time and while ensuring high code quality. In this tutorial, learn how to run multiple NUnit test cases in parallel.
January 13, 2026
This article is a part of our Content Hub. For more in-depth resources, check out our content hub on Selenium NUnit Tutorial.
When it comes to automated testing in .NET, the NUnit framework is a go-to choice due to its simplicity and robust set of features. In this blog, I will show you how to run multiple test cases in NUnit and Selenium.
Why Use NUnit for Selenium C#?
NUnit, a popular testing framework for .NET, simplifies automated testing in Selenium C#. It allows testers to run multiple test cases efficiently, validate user actions, and ensure software quality across various scenarios.
What is NUnit?
NUnit is an open-source unit testing framework for .NET, enabling developers to test their code easily with features like assertions, parameterized tests, and test fixtures. It follows the xUnit model for organizing tests:
Running Multiple NUnit Test Cases
NUnit supports running multiple test cases in parallel to improve efficiency and test coverage. Using attributes like [TestCase] and [Parallelizable], you can run the same test with different inputs or in parallel to save time:
Best Practices for Selenium C# Testing
Here are some best practices to ensure effective and efficient testing with Selenium in C#:
When working on complex projects, having multiple NUnit test cases to cover various scenarios and edge cases is common. NUnit provides methods to automate the execution of multiple test cases, saving time and effort while maintaining high code quality.
In the following sections, we will explore how to organize and structure test cases and execute them in bulk using attributes and data-driven testing. We will cover what NUnit is, how to run the same test with different test data, and how to run multiple NUnit test cases in parallel. Ultimately, we’ll have a short example of how all this information can be put together. If you are preparing for an interview you can learn more through NUnit interview questions.
Before demonstrating how to run multiple test cases in NUnit, let’s understand what NUnit is and why it’s a popular framework for automation testing.
NUnit is an open-source unit testing framework for .NET languages, including C# and VB.NET. When writing this blog on running multiple NUnit test cases, the latest version is 3.13.3. NUnit provides a simple and intuitive way to write and execute tests, allowing you to verify the behavior and code correctness.
NUnit follows the xUnit testing framework pattern, separating test setup, execution, and assertions.
One of NUnit’s main benefits is its compatibility with popular development environments like Visual Studio, which makes it a practical option for testing frameworks in .NET.
We will discuss its range of properties and NUnit assertions that help organize and structure tests. To increase flexibility and test coverage, NUnit also offers additional features like:
Now that we have a basic understanding of this framework, let’s look at what are annotations in NUnit. After that, we will see how to run multiple NUnit test cases.
Getting started with Selenium testing with NUnit? Watch the tutorial below and expedite your learning.
Subscribe to our TestMu AI YouTube Channel for the latest updates on tutorials around Selenium testing, Cypress testing, and more.
NUnit annotations, also called NUnit attributes, are special instructions or metadata that can be applied to test methods, classes, or assembly files to modify code execution or provide additional information, like descriptions and test case links (for integration with test management tools like TestRail).
The most common NUnit annotations are:
The order in which the methods are executed is as follows:
[OneTimeSetup]
[Setup]
TestMethod1
[TearDown]
[Setup]
TestMethod2
[TearDown]
[OneTimeTearDown]
Note: Run your Selenium NUnit tests across 3000+ real environments. Try TestMu AI Today!
Data-driven testing is an approach to testing a software application using multiple input data sets. Instead of writing separate test methods for each data set, we can leverage NUnit’s data-driven testing feature to run a single test method with different inputs. This technique is especially useful when we want to test code against various scenarios or validate different data combinations, for example, cross browser testing.
Here’s an example of how to perform data-driven testing with NUnit using the TestCase attribute:
public class Tests
{
[Test]
[TestCase("Chrome")]
[TestCase("Safari")]
[TestCase("Edge")]
public void TestOnMultipleBrowsers(string browser)
{
// Test code goes here
}
}
In the above code, we have a Tests class with a TestOnMultipleBrowsers method containing code we want to run on multiple browsers. Instead of writing separate tests for each input/output pair, we use the [TestCase] attribute to specify multiple sets of input and expected output. NUnit will run the TestAddMethod test method three times, once for each test case.
The [TestCase] attribute also supports a variety of data sources, such as arrays, data tables, and CSV files. Here’s an example of using a data table with the TestCaseSource attribute:
public class Tests
{
static object[] ItemData =
{
new object[] { new Item("Chrome", 114)},
new object[] { new Item("Safari", 16.5)},
new object[] { new Item("Edge", 114)},
};
[Test]
[TestCaseSource(nameof(ItemData))]
public void TestOnMultipleBrowsers(Item item)
{
// Test code goes here
}
}
In this example, we have a class with a test method that uses a data table to define multiple browsers and browser versions.
We then use the TestCaseSource attribute to specify that NUnit should use the ItemData field as the data source for the test method. Again, NUnit will run the test method three times, once for each set of inputs.
By default, test cases in NUnit are run sequentially, meaning that a new test will only run after the previous one has completed its execution. This is all good when we don’t have a lot of tests, but as the projects get more complex, we want to save time on the test execution. To do this, we can run the tests in parallel.
For parallelization, NUnit offers the annotation [Parallelizable] annotation, which can be used at the class level or at the method level. We, the designers of the tests, are in charge of ensuring that the tests are thread safe when executed concurrently.
Otherwise, unexpected behavior can result from concurrent tests that edit instance fields or properties without locks, just like it would in a multi-threaded program. This applies to scenarios where one test case can change the data used in a different test case. Keeping the tests as independent as possible is always a good practice.
When using the [Parallelizable] annotation, we need to specify the scope of the parallelization. Here are the available options:
In the next section of this NUnit tutorial, I will demo how we can use data-driven testing with Selenium and run multiple NUnit test cases in parallel, saving a lot of execution time. We will be using the already-mentioned annotations, assertions, and data-driven testing. This is equivalent to executing multiple NUnit test cases.
Scenario 1:
Scenario 2:
When writing this article, the latest version of Selenium is 4.10.0. One of the standout features in Selenium 4 is the adoption of the W3C WebDriver protocol, which takes the place of the JSON wire protocol used in Selenium 3. This shift has been a game-changer, making Selenium 4 distinct and more advanced compared to Selenium 3.
To know the difference between Selenium 3 and 4 versions, we recommend checking our article on Selenium 3 vs Selenium 4.
Let’s see how to run multiple NUnit test cases on a local machine. There are a few prerequisites before we start writing the tests.
First, create a new NUnit project:

Next, add the Selenium.WebDriver Nuget package. Also, add a NuGet package for the desired browser. As I use the Chrome browser, I will now add the Selenium.WebDriver.ChromeDriver package. I am also adding the package DotNetSeleniumExtras, which will be used for explicit waits in Selenium.
Once we are done with the above prerequisites, the next step is to write the test script.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using SeleniumExtras.WaitHelpers;
using OpenQA.Selenium.Support.UI;
namespace NUnitDataDriven
{
public class NUnitTest
{
private static IWebDriver driver;
[SetUp]
public void Setup()
{
driver = new ChromeDriver();
}
[Test]
[TestCase("Components")]
[TestCase("Cameras")]
[TestCase("Software")]
public void OpenCategory(string menuOption)
{
driver.Navigate().GoToUrl("https://ecommerce-playground.lambdatest.io/");
driver.FindElement(By.XPath("//a[normalize-space()='Shop by Category']")).Click();
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
string xpath = $"//span[normalize-space()='{menuOption}']";
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath)));
driver.FindElement(By.XPath(xpath)).Click();
Assert.That(Equals(driver.Title, menuOption));
}
[Test]
[TestCase("andreea", "test")]
[TestCase("[email protected]", "")]
[TestCase("[email protected]", "xxxx")]
public void LoginInvalidCredentials(string email, string password)
{
driver.Navigate().GoToUrl("https://ecommerce-playground.lambdatest.io/index.php?route=account/login");
driver.FindElement(By.Name("email")).SendKeys(email);
driver.FindElement(By.Id("input-password")).SendKeys(password);
driver.FindElement(By.CssSelector("input[value='Login']")).Click();
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
string xpath = "//div[@class='alert alert-danger alert-dismissible']";
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath)));
Assert.That(driver.FindElement(By.XPath(xpath)).Text.Contains("No match for E-Mail Address and/or Password."));
}
[TearDown]
public void TearDown()
{
driver.Quit();
}
}
}

The first part is the same for all C# classes and contains the references to namespaces and packages to be used:

Then, we have the driver variable declared in the first part of the class using the IWebDriver Selenium interface:

We don’t need any other variables for this example, so we can go straight to the tests. However, we can use a common setup for all our tests to avoid code repetition in each test. We’ll do this using the [SetUp] annotation, so the code inside will execute before each test case. This line of code simply starts the Chrome browser.

Next, we can get started on the tests. We have two scenarios that will be executed with various test data. So we will have the [Test] annotation to instruct the test runner that the code inside is test code and the [TestCase] annotation, once for each set of data.
Let’s look at them individually:

In this test, we need to declare a string variable for selecting the menu option. We can call it menuOption, and inside each test case annotation, we need to pass the string value to use.
The first step of the test is to navigate to the desired URL using the Navigate Selenium command. After the page is loaded, we need to click the Shop by Category link – for this, we will use the FindElement() command to identify the web element using its XPath and the Click() command to perform the click.
Next, we want to click the category, but we can instruct Selenium to wait for the link to be visible before clicking it. For this, we can use an explicit wait, and the click will not be performed before the element is loaded on the page. We can use XPath again to identify the element and the Click() command to click on it.
The last step is the assertion, using the NUnit class Assert, and we want to validate that the correct page is loaded. For this, we compare the page title with the menu option, and these two strings should be equal.
In the second test case, we will need two variables – one for the user email and one for the password, and we will pass the values the same way we did in the previous test.

The first line is the same as in the other test, except we navigate to a different URL.

Next, we need to identify the email and password fields, enter their values, and click the Login button. We can use Locators in Selenium to find the elements, such as Name, ID, or CSS Selectors.

Next, we again need Selenium Waits to ensure that the validation is not done before the warning is visible on the web page.

The last line is an assertion, which contains the validation that the correct message is displayed.

And last but not least, we have a teardown method that executes after each test case due to the [TearDown] annotation. We are closing the browser after each execution, using the Quit() command.

The tests can be run from the Test Explorer panel – you can see that each set of data is displayed as a separate test and can be run independently.

If you run all the tests, they will run sequentially, each test opening a new Chrome browser window. Running them in parallel can cause issues because each test tries to interact and simulate mouse and keyboard actions.

After running the tests, you can see the total time is almost 40 seconds – not more, but this is a sample project with simple tests. The more tests the project has, the longer it will take to execute them locally, and this means that the local machine cannot be used during this time.
Note: Perform NUnit automation testing on cloud Selenium grid. Try TestMu AI Today!
Let’s see how to write the tests, but this time for running them on the online Selenium grid offered by TestMu AI – an AI-powered test orchestration and execution platform to perform automated testing with NUnit at scale on over 3000+ real browsers and operating systems. With TestMu AI, you can run multiple NUnit test cases in parallel, reduce test execution time, and ramp up the feedback loop for deploying quality builds.
Looking to get started with Selenium automation with NUnit? Check out the documentation – NUnit with Selenium.
So you can test remotely and not on a local machine. To run the test on TestMu AI, first, we need to use the Capabilities Generator to set up the browser capabilities.

Here is how the code looks this time.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.UI;
using SeleniumExtras.WaitHelpers;
[assembly:Parallelizable(ParallelScope.All)]
namespace NUnitDataDriven
{
public class NUnitTest
{
ThreadLocal<IWebDriver> driver = new ThreadLocal<IWebDriver>();
public static string gridURL = "@hub.lambdatest.com/wd/hub";
public static string testURL_1 = "https://ecommerce-playground.lambdatest.io/";
public static string testURL_2 = "https://ecommerce-playground.lambdatest.io/index.php?route=account/login";
private static readonly string LT_USERNAME = Environment.GetEnvironmentVariable("LT_USERNAME");
private static readonly string LT_ACCESS_KEY = Environment.GetEnvironmentVariable("LT_ACCESS_KEY");
[SetUp]
public void Setup()
{
ChromeOptions capabilities = new ChromeOptions();
capabilities.BrowserVersion = "latest";
Dictionary<string, object> ltOptions = new Dictionary<string, object>();
ltOptions.Add("username", LT_USERNAME);
ltOptions.Add("accessKey", LT_ACCESS_KEY);
ltOptions.Add("platformName", "Windows 11");
ltOptions.Add("project", "NUnit Multiple Tests");
ltOptions.Add("w3c", true);
ltOptions.Add("plugin", "c#-c#");
capabilities.AddAdditionalOption("LT:Options", ltOptions);
driver.Value = new RemoteWebDriver(new Uri($"https://{LT_USERNAME}:{LT_ACCESS_KEY}{gridURL}"), capabilities);
}
[Test]
[TestCase("Components")]
[TestCase("Cameras")]
[TestCase("Software")]
public void OpenCategory(string menuOption)
{
IWebDriver currentDriver = driver.Value;
currentDriver.Manage().Window.Maximize();
currentDriver.Navigate().GoToUrl(testURL_1);
currentDriver.FindElement(By.XPath("//a[normalize-space()='Shop by Category']")).Click();
WebDriverWait wait = new WebDriverWait(currentDriver, TimeSpan.FromSeconds(5));
string xpath = $"//span[normalize-space()='{menuOption}']";
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath)));
currentDriver.FindElement(By.XPath(xpath)).Click();
Assert.That(Equals(currentDriver.Title, menuOption));
}
[Test]
[TestCase("andreea1", "test")]
[TestCase("[email protected]", "")]
[TestCase("[email protected]", "xxxx")]
public void LoginInvalidCredentials(string email, string password)
{
IWebDriver currentDriver = driver.Value;
currentDriver.Navigate().GoToUrl(testURL_2);
currentDriver.FindElement(By.Name("email")).SendKeys(email);
currentDriver.FindElement(By.Id("input-password")).SendKeys(password);
currentDriver.FindElement(By.CssSelector("input[value='Login']")).Click();
WebDriverWait wait = new WebDriverWait(currentDriver, TimeSpan.FromSeconds(5));
string xpath = "//div[@class='alert alert-danger alert-dismissible']";
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath)));
Assert.That(currentDriver.FindElement(By.XPath(xpath)).Text.Contains("No match for E-Mail Address and/or Password."));
}
[TearDown]
public void Cleanup()
{
bool passed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed;
try
{
// Logs the result to Lambdatest
((IJavaScriptExecutor)driver.Value).ExecuteScript("lambda-status=" + (passed ? "passed" : "failed"));
}
finally
{
// Terminates the remote webdriver session
driver.Value.Quit();
}
}
}
}
Just like before, the first lines of code contain the references used in the class – this time, we need an additional reference, OpenQA.Selenium.Remote, which allows us to run the tests remotely:

Before the class name, we use the [assembly:Parallelizable(ParallelScope.All)] attribute, which will instruct the tests contained in the class to run in parallel with each other.

Next, we have the variables declaration for the variables we will use: the driver, the test URLs, your TestMu AI username and access key, which are stored as environment variables, and the grid URL.

Then, there is the [Setup]. In this method, we define the capabilities used when running the tests.

In the test, the only change is that we need to create a new variable for the current instance of the driver and use it in the interactions with the browser:

And in the teardown, before closing the browser, we also want to make sure that the results are saved to TestMu AI:

The rest of the code is the same.
Running multiple NUnit test cases in parallel on TestMu AI will help you reap the following benefits:
Starting the test execution on the TestMu AI cloud grid can be done the same way as the local execution by selecting to run the tests from the Test Explorer. This time, the execution will be done on the remote server, leaving the local machine available for other work.
Also, parallel execution of multiple NUnit test cases will depend on the number of allowed parallel tests in your TestMu AI account.
After running the multiple NUnit test cases in parallel, you can see both results in the Test Explorer. You can also see them in the browser, including a video recording of the test and details about the Selenium WebDriver NUnit commands that were sent.


In this blog on running multiple NUnit test cases, we explored the powerful capabilities of NUnit for running multiple tests using data-driven testing and parallelization. By leveraging these features, we can write more efficient and comprehensive test suites that cover a wide range of scenarios and data combinations.
Data-driven testing allows us to test our code with multiple input datasets without writing separate test methods for each case. Using the [TestCase] attribute, we can pass different test case data and quickly validate the expected results.
This approach saves time and effort and promotes maintainability by keeping our test code concise and focused. Additionally, with NUnit, we can run our tests in parallel, which significantly reduces the overall test execution time, especially if we have a large number of tests.
By utilizing multiple threads or processes, NUnit can distribute the workload and execute tests concurrently, leading to faster feedback and quicker test cycles. Remember, when using parallelization, it’s important to ensure that the tests are thread-safe and do not have any unintended dependencies or side effects.
In conclusion, NUnit offers robust features for running multiple tests using data-driven testing and parallelization. By adopting these techniques, we can enhance the efficiency and effectiveness of the test suite, resulting in improved code quality and faster delivery cycles. So go ahead, explore these features, and unlock the full potential of NUnit for your testing needs!
Author
Did you find this page helpful?
More Related Hubs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance