Parallel tests with NUnit, each test case executed only once
Let's say we have a TestFixture
class containing 3 Test
/TestCase
methods, which we want to execute in parallel on 3 devices. With the approach described in Parallel test execution in Visual Studio using NUnit, each Test
/TestCase
method would run once per device, on each device, as shown in the following table:
device # 1 |
test # 1 |
test # 2 |
test # 3 |
---|---|---|---|
device # 2 |
test # 1 |
test # 2 |
test # 3 |
device # 3 |
test # 1 |
test # 2 |
test # 3 |
If we want each Test
/TestCase
method in the TestFixture
class to run only once in general and on only one of the devices available for parallel execution, as shown in the following table, it would not work to include the driver setup in the TestFixture
class (as in the example included in Parallel test execution in Visual Studio using NUnit) because a single instance of the TestFixture
class would be used for all Test
/TestCase
methods it contains. Therefore, it would not be possible to have the driver sessions for each Test
/TestCase
method run in separate threads.
device # 1 |
test # 1 |
---|---|
device # 2 |
test # 2 |
device # 3 |
test # 3 |
To overcome this issue, we would need to create a separate Test Base
class where we define the driver and create/destroy the driver session. Then, in each Test
/TestCase
method in the Parallelizable TestFixture
class, you would create and use a separate instance of that Test Base
class.
Following is a simple example of such a Test Base
class, with Reportium included, followed by a simple example of a TestFixture
class with two Test
methods that would run in parallel.
The level of parallelism here is Parallelizable(ParallelScope.All)
.
Example of a simple Test Base class
using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium.Android;
using OpenQA.Selenium.Remote;
using Reportium.client;
using Reportium.model;
using OpenQA.Selenium.Appium;
using Reportium.test.Result;
namespace MobileTest_NUnit
{
class TestSetup
{
private AppiumDriver<IWebElement> driver;
private ReportiumClient reportiumClient;
//replace <your_security_token> with your security token for the cloud
//see ../Perfecto/automation-testing/generate_security_tokens.htm
private const String securityToken = "<your_security_token>";
//replace <your_cloud_name> with the name of your cloud
private const String cloudName = "<your_cloud_name>";
//create the driver session with the Constructor of the TestSetup class
public TestSetup(String platformName, String platformVersion)
{
DesiredCapabilities capabilities = new DesiredCapabilities();
//run the tests on devices of the specified platform
capabilities.SetCapability("platformName", platformName);
capabilities.SetCapability("platformVersion", platformVersion);
//authenticate to the Perfecto cloud
capabilities.SetCapability("securityToken", securityToken);
//create driver session
var url = new Uri(string.Format("https://" + cloudName + ".perfectomobile.com/nexperience/perfectomobile/wd/hub"));
driver = new AndroidDriver<IWebElement>(url, capabilities);
//driver = new IOSDriver<IWebElement>(url, capabilities);
// Reporting client. For more details, see ../Perfecto/test-analysis/test_analysis_with_smart_reporting.htm
PerfectoExecutionContext perfectoExecutionContext = new PerfectoExecutionContext.PerfectoExecutionContextBuilder()
.withProject(new Project("My Project", "1.0"))
.withContextTags(new[] { "tag1" })
.withWebDriver(driver)
.build();
reportiumClient = PerfectoClientFactory.createPerfectoReportiumClient(perfectoExecutionContext);
}
public AppiumDriver<IWebElement> GetDriver()
{
return driver;
}
public void Start(String name, Reportium.test.TestContextTags contextTags)
{
reportiumClient.testStart(name, contextTags);
}
public void ReportSuccess()
{
reportiumClient.testStop(TestResultFactory.createSuccess());
}
public void ReportFailure(Exception e)
{
reportiumClient.testStop(TestResultFactory.createFailure(e.Message, e));
}
public void Stop()
{
driver.Close();
driver.Quit();
// Retrieve the URL of the Single Test Report and print it to the Console
String reportURL = reportiumClient.getReportUrl();
Console.WriteLine(reportURL);
// For documentation on how to export reporting PDF, see https://github.com/perfectocode/samples/wiki/reporting
//String reportPdfUrl = (String)(driver.Capabilities.GetCapability("reportPdfUrl"));
// For detailed documentation on how to export the Execution Summary PDF Report, the Single Test report and other attachments such as
// video, images, device logs, vitals and network files - see ../Perfecto/test-analysis/export_reports.htm
}
}
}
Example of a simple TestFixture class
using System;
using System.Collections.Generic;
using Reportium.test;
using NUnit.Framework;
namespace MobileTest_NUnit
{
//run the tests in parallel on Android 8 devices; each test would run only once
[TestFixture("Android", "8.0.0")]
[Parallelizable(ParallelScope.All)]
public class AppiumTest
{
private String platformName, platformVersion;
public AppiumTest(String platformName, String platformVersion)
{
this.platformName = platformName;
this.platformVersion = platformVersion;
}
//sample test to open the Android Settings app and find the 'Connections' element (Native)
[Test]
public void SettingsTest()
{
var test = new TestSetup(this.platformName, this.platformVersion);
test.Start("SettingsTest", new TestContextTags("NUnit", "Parallel"));
try
{
Dictionary<String, Object> pars = new Dictionary<String, Object>();
pars.Add("name", "Settings");
test.GetDriver().ExecuteScript("mobile:application:open", pars);
test.GetDriver().Context = "NATIVE_APP";
test.GetDriver().FindElementByXPath("//*[@text='Connections']");
test.ReportSuccess();
}
catch (Exception exception)
{
test.ReportFailure(exception);
}
test.Stop();
}
//sample test to open the browser, navigate to Perfecto web page, and find the brand image (Web)
[Test]
public void PerfectoIOTest()
{
var test = new TestSetup(this.platformName, this.platformVersion);
test.Start("PerfectoIOTest", new TestContextTags("NUnit", "Parallel"));
try
{
test.GetDriver().Navigate().GoToUrl("https://www.perfecto.io");
test.GetDriver().Context = "WEBVIEW";
test.GetDriver().FindElementById("block-perfecto-branding");
test.ReportSuccess();
}
catch (Exception exception)
{
test.ReportFailure(exception);
}
test.Stop();
}
}
}