Run Tests in Parallel
Run C# tests in parallel to achieve faster builds
On BrowserStack, you can run multiple Selenium Webdriver tests at the same time across various browser, device and OS combinations. This is “Parallel Testing”. Parallel Testing gives you the same benefits as running a multi-threaded application.
With Parallel Testing, you can run the same test on different browser/device combinations i.e. cross-browser testing, or run different tests on the same or different browser/device combinations. Parallel Testing will help you reduce the run time of your test suite, resulting in faster build times and faster releases.
You can start testing in parallel using one of the popular test frameworks which work with C# and Selenium or refer the following section. We have provided getting started guides on some of the popular frameworks below:
Run tests in parallel without a framework
You can achieve parallel testing in multiple ways even if you are not using one of the popular test frameworks which has feature for enabling parallel testing. We show two such ways below but this is not an exhaustive list:
- Using a multi-threaded program
- Using a multi-threaded program and using ThreadPoolExecutor to manage threads
Using a multi-threaded program
The following sample script shows a multi-threaded C# program. These are the salient points of the script:
- The same script is run across several browser and OS combinations.
- The
sampleTestCase
function passes capabilities toexecutetestwithcaps
function based on the browser. - The
executetestwithcaps
function takes capabilities as the argument and executes the same script on each set of capability as parallel sessions.
using System.Threading;
using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Support.UI;
namespace SeleniumTest
{
class Program
{
static void Main(string[] args)
{
Thread device1 = new Thread(obj => sampleTestCase("Safari", "latest", null, "14", "iPhone 12 Pro Max", "true", "iPhone 12 Pro Max - safari latest", "Parallel-build-csharp"));
Thread device2 = new Thread(obj => sampleTestCase("Chrome", "latest", null, null, "Samsung Galaxy S20", "true", "Samsung Galaxy S20 - Chrome latest", "Parallel-build-csharp"));
Thread device3 = new Thread(obj => sampleTestCase("Firefox", "latest", "OSX", "Monterey", null, null, "macOS Monterey - Firefox latest", "Parallel-build-csharp"));
Thread device4 = new Thread(obj => sampleTestCase("Safari", "latest", "OSX", "Big Sur", null, null, "macOS Big Sur - Safari latest", "Parallel-build-csharp"));
Thread device5 = new Thread(obj => sampleTestCase("Edge", "latest", "Windows", "10", null, null, "Windows - Edge latest", "Parallel-build-csharp"));
//Executing the methods
device1.Start();
device2.Start();
device3.Start();
device4.Start();
device5.Start();
device1.Join();
device2.Join();
device3.Join();
device4.Join();
device5.Join();
}
static void sampleTestCase(String browser, String browser_version, String os, String os_version, String device, String realmobile, String test_name, String build_name)
{
switch (browser)
{
case "Safari": //If browser is Safari, following capabilities will be passed to 'executetestwithcaps' function
OpenQA.Selenium.Safari.SafariOptions safariCapability = new OpenQA.Selenium.Safari.SafariOptions();
safariCapability.AddAdditionalCapability("os_version", os_version);
safariCapability.AddAdditionalCapability("browser", browser);
safariCapability.AddAdditionalCapability("browser_version", browser_version);
safariCapability.AddAdditionalCapability("os", os);
safariCapability.AddAdditionalCapability("device", device);
safariCapability.AddAdditionalCapability("realMobile", realmobile);
safariCapability.AddAdditionalCapability("name", test_name); // test name
safariCapability.AddAdditionalCapability("build", build_name); // Your tests will be organized within this build
safariCapability.AddAdditionalCapability("browserstack.user", "YOUR_USERNAME");
safariCapability.AddAdditionalCapability("browserstack.key", "YOUR_ACCESS_KEY");
executetestwithcaps(safariCapability);
break;
case "Chrome": //If browser is Chrome, following capabilities will be passed to 'executetestwithcaps' function
OpenQA.Selenium.Chrome.ChromeOptions chromeCapability = new OpenQA.Selenium.Chrome.ChromeOptions();
chromeCapability.AddAdditionalCapability("os_version", os_version, true);
chromeCapability.AddAdditionalCapability("browser", browser, true);
chromeCapability.AddAdditionalCapability("browser_version", browser_version, true);
chromeCapability.AddAdditionalCapability("os", os, true);
chromeCapability.AddAdditionalCapability("device", device, true);
chromeCapability.AddAdditionalCapability("realMobile", realmobile, true);
chromeCapability.AddAdditionalCapability("name", test_name, true);
chromeCapability.AddAdditionalCapability("build", build_name, true);
chromeCapability.AddAdditionalCapability("browserstack.user", "YOUR_USERNAME", true);
chromeCapability.AddAdditionalCapability("browserstack.key", "YOUR_ACCESS_KEY", true);
executetestwithcaps(chromeCapability);
break;
case "Firefox": //If browser is Firefox, following capabilities will be passed to 'executetestwithcaps' function
OpenQA.Selenium.Firefox.FirefoxOptions firefoxCapability = new OpenQA.Selenium.Firefox.FirefoxOptions();
firefoxCapability.AddAdditionalCapability("os_version", os_version, true);
firefoxCapability.AddAdditionalCapability("browser", browser, true);
firefoxCapability.AddAdditionalCapability("browser_version", browser_version, true);
firefoxCapability.AddAdditionalCapability("os", os, true);
firefoxCapability.AddAdditionalCapability("name", test_name, true);
firefoxCapability.AddAdditionalCapability("build", build_name, true);
firefoxCapability.AddAdditionalCapability("browserstack.user", "YOUR_USERNAME", true);
firefoxCapability.AddAdditionalCapability("browserstack.key", "YOUR_ACCESS_KEY", true);
executetestwithcaps(firefoxCapability);
break;
case "Edge": //If browser is Edge, following capabilities will be passed to 'executetestwithcaps' function
OpenQA.Selenium.Edge.EdgeOptions edgecapability = new OpenQA.Selenium.Edge.EdgeOptions();
edgecapability.AddAdditionalCapability("os_version", os_version);
edgecapability.AddAdditionalCapability("browser", browser);
edgecapability.AddAdditionalCapability("browser_version", browser_version);
edgecapability.AddAdditionalCapability("os", os);
edgecapability.AddAdditionalCapability("name", test_name);
edgecapability.AddAdditionalCapability("build", build_name);
edgecapability.AddAdditionalCapability("browserstack.user", "YOUR_USERNAME");
edgecapability.AddAdditionalCapability("browserstack.key", "YOUR_ACCESS_KEY");
executetestwithcaps(edgecapability);
break;
default: //If browser is IE, following capabilities will be passed to 'executetestwithcaps' function
OpenQA.Selenium.IE.InternetExplorerOptions ieCapability = new OpenQA.Selenium.IE.InternetExplorerOptions();
ieCapability.AddAdditionalCapability("os_version", os_version, true);
ieCapability.AddAdditionalCapability("browser", browser, true);
ieCapability.AddAdditionalCapability("browser_version", browser_version, true);
ieCapability.AddAdditionalCapability("os", os, true);
ieCapability.AddAdditionalCapability("name", test_name, true);
ieCapability.AddAdditionalCapability("build", build_name, true);
ieCapability.AddAdditionalCapability("browserstack.user", "YOUR_USERNAME", true);
ieCapability.AddAdditionalCapability("browserstack.key", "YOUR_ACCESS_KEY", true);
executetestwithcaps(ieCapability);
break;
}
}
//executetestwithcaps function takes capabilities from 'sampleTestCase' function and executes the test
static void executetestwithcaps(DriverOptions capability)
{
IWebDriver driver = new RemoteWebDriver(new Uri("https://hub-cloud.browserstack.com/wd/hub/"), capability);
try
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
driver.Navigate().GoToUrl("https://bstackdemo.com/");
// getting name of the product
String product_on_page = wait.Until(driver => driver.FindElement(By.XPath("//*[@id=\"1\"]/p"))).Text;
// clicking the 'Add to Cart' button
IWebElement cart_btn = driver.FindElement(By.XPath("//*[@id='1']/div[4]"));
wait.Until(driver => cart_btn.Displayed);
cart_btn.Click();
// waiting for the Cart pane to appear
wait.Until(driver => driver.FindElement(By.ClassName("float-cart__content")).Displayed);
// getting name of the product in the cart
String product_in_cart = driver.FindElement(By.XPath("//*[@id='__next']/div/div/div[2]/div[2]/div[2]/div/div[3]/p[1]")).Text;
if (product_on_page == product_in_cart)
{
((IJavaScriptExecutor)driver).ExecuteScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\":\"passed\", \"reason\": \" Product has been successfully added to the cart!\"}}");
}
}
catch
{
((IJavaScriptExecutor)driver).ExecuteScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\":\"failed\", \"reason\": \" Some elements failed to load.\"}}");
}
driver.Quit();
}
}
}
Using a multi-threaded program and using ThreadPoolExecutor to manage threads
In case of the above implementation, all the threads are dispatched at the same time. You can also manage the dispatching of threads by applying additional conditions, but, in that case, you would have to manually keep track of which thread has completed its execution and depending on that, you will be required to spawn new threads keeping in mind you do not exceed the limit of parallel tests that is supported by your BrowserStack account.
You can choose to not manage the threads manually and use the C# ThreadPool to do the same for you by following the steps mentioned in the documentation for threadpool in C#
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
We're sorry to hear that. Please share your feedback so we can do better
Contact our Support team for immediate help while we work on improving our docs.
We're continuously improving our docs. We'd love to know what you liked
Thank you for your valuable feedback!