Page tree
Skip to end of metadata
Go to start of metadata

Last updated: Jul 03, 2019 10:18

The approach is same as in Parallel tests with NUnit, each test case executed only once, here translated to Java TestNG.

It is applicable when we have several test cases in a class, and we wish to execute those in parallel on available devices of specific type - with each test case executed only once.

I.e. as in this table:

device # 1

test # 1

test # 4

device # 2

test # 2

test # 5

device # 3

test # 3



To achieve this, we need to set the parallel scope to "methods" level in the testng.xml file.

(As opposed to Parallel Execution with TestNG where the parallel scope is "tests" level and all the test cases in a class run once per device)

Here is a sample example of such testng.xml file, where we specify the type of devices on which to execute the test cases via the device model parameter:

<?xml version="1.0" encoding="UTF-8"?>
<suite name="Suite" parallel="methods">
  <test name="MyTest">
  <parameter name="deviceModel" value="Galaxy S8" />
    <classes>
      <class name="testng.MyTest"/>
    </classes>
  </test> <!-- Test -->
</suite> <!-- Suite -->


As explained in above mentioned article about NUnit, here as well we would need to create a separate Test Base class. This is where we define the driver, and create/destroy the driver session.

Thus we would be able to separate the driver session thread per test case level, not per class level as in Parallel Execution with TestNG

Following is a very simple example of such Test Base class, with Reportium included:

package testng;

import java.net.MalformedURLException;
import java.net.URL;

import org.openqa.selenium.remote.DesiredCapabilities;

import com.perfecto.reportium.client.ReportiumClient;
import com.perfecto.reportium.client.ReportiumClientFactory;
import com.perfecto.reportium.model.PerfectoExecutionContext;
import com.perfecto.reportium.model.Project;
import com.perfecto.reportium.test.TestContext;
import com.perfecto.reportium.test.result.TestResultFactory;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;

public class TestSetup {
	
	private AppiumDriver driver;
	private ReportiumClient reportiumClient;
	
    //replace <your_security_token> with your security token for the cloud
    //see https://developers.perfectomobile.com/display/PD/Security+Token
	private final String securityToken = "<your_security_token>";
	
	//replace <your_cloud_name> with the name of your cloud
	private final String cloudName = "<your_cloud_name>";
	
	//create the driver session with the Constructor of the TestSetup class
	public TestSetup(String deviceModel) {
		DesiredCapabilities capabilities = new DesiredCapabilities();
		
		capabilities.setCapability("securityToken", this.securityToken);
		
		//run the tests on devices of the specified model
		capabilities.setCapability("model", deviceModel);
		
		//create driver session in 60 retries per 1 second interval
		//see https://developers.perfectomobile.com/pages/viewpage.action?pageId=21430899
		//modify the values according to your tests' expected duration
		int retry = 60;
		int interval = 1000;
		while(retry > 0 && driver==null) {
			  try {
				  driver = new AndroidDriver(new URL("https://" + this.cloudName + ".perfectomobile.com/nexperience/perfectomobile/wd/hub"), capabilities);
			  } catch (Exception e) {
			    /* Decrement Retry */
			      retry--;
			      System.out.println("Attempt: " + (60-retry) + ". Failure to Acquire device, Retrying....." + e);
			      try {
					Thread.sleep(interval);
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			  }
		}
		
        // Reporting client. For more details, see http://developers.perfectomobile.com/display/PD/Reporting
        // And https://developers.perfectomobile.com/pages/viewpage.action?pageId=12419423
        PerfectoExecutionContext perfectoExecutionContext = new PerfectoExecutionContext.PerfectoExecutionContextBuilder()
                .withProject(new Project("My Project", "1.0"))
                .withContextTags("tag1")
                .withWebDriver(driver)
                .build();
        reportiumClient = new ReportiumClientFactory().createPerfectoReportiumClient(perfectoExecutionContext);
	}
	
	public AppiumDriver getDriver() {
		return this.driver;
	}
	
	public void reportStart(String testName, TestContext context) {
		reportiumClient.testStart(testName, context);
	}
	
	public void reportSuccess() {
		reportiumClient.testStop(TestResultFactory.createSuccess());
	}
	
	public void reportFailure(Exception e) {
		reportiumClient.testStop(TestResultFactory.createFailure(e.getMessage(), e));
	}
	
	public void stop() {
		try {
			//close the driver session
			driver.close();
			driver.quit();
			
			//retrieve the URL of the Single Test Report and print it to the console
            String reportURL = reportiumClient.getReportUrl();
            System.out.println(reportURL);
			
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

}


And, below is the relevant example of a TestNG class with 3 test cases.

We have separate instance of the TestSetup class for each of the test cases.

Thus we can have the test cases start in parallel on available devices of the specified type (via device model in this example).

package testng;

import java.util.HashMap;
import java.util.Map;

import org.testng.annotations.Test;
import org.testng.annotations.Parameters;
import org.testng.annotations.BeforeClass;

import com.perfecto.reportium.test.TestContext;

public class MyTest {
	
	private String deviceModel;
		
	@Parameters({"deviceModel"})
	@BeforeClass
	public void beforeClass(String deviceModel) {
			  
		this.deviceModel = deviceModel;
	}
		
	//sample test to open the browser, navigate to Perfecto.io web page, and find the heading (Web)
	@Test
	public void test1() {
		  
	TestSetup test = new TestSetup(this.deviceModel);
		  
		try {
			test.reportStart("Test #1", new TestContext("Sample"));
				  
			test.getDriver().get("https://www.perfecto.io");
				
			test.getDriver().context("WEBVIEW");
				
			test.getDriver().findElementsByXPath("//*[text()='Web & Mobile App Testing']");
				
			test.reportSuccess();
				  
		} catch (Exception e) {
				
			test.reportFailure(e);
			e.printStackTrace();
		}
		  
		test.stop();
	}
	 
	//sample test to open the Android Settings app and find the 'Connections' element (Native)
	@Test
	public void test2() {
		  
		TestSetup test = new TestSetup(this.deviceModel);
		  
		try {
			test.reportStart("Test #2", new TestContext("Sample"));
				  
			Map<String, Object> params = new HashMap<>();
			params.put("name", "Settings");
			test.getDriver().executeScript("mobile:application:open", params);
				
			test.getDriver().context("NATIVE_APP");
				
			test.getDriver().findElementsByXPath("//*[@text='Connections']");
				
			test.reportSuccess();
			
		} catch (Exception e) {
			
			test.reportFailure(e);
			e.printStackTrace();
		}
		  
		test.stop();
	}
	  
	//sample test to go to device Home screen and check whether the 'Internet' icon is present
	@Test
	public void test3() {
		  
		TestSetup test = new TestSetup(this.deviceModel);
		  
		try {
			test.reportStart("Test #3", new TestContext("Sample"));
				  
			Map<String, Object> params5 = new HashMap<>();
			test.getDriver().executeScript("mobile:handset:ready", params5);
				
			Map<String, Object> params6 = new HashMap<>();
			params6.put("content", "Internet");
			params6.put("timeout", "20");
			test.getDriver().executeScript("mobile:checkpoint:text", params6);
				
			test.reportSuccess();
			
		} catch (Exception e) {
			
			test.reportFailure(e);
			e.printStackTrace();
		}
		
		test.stop();
	}
}