I am currently working on cucumber automation parallel execution of the Runner class and I came across this nice framework http://comcast.github.io/zucchini/ and I am facing some issues with running my AndroidDriver test cases in parallel. When I run my code using via pom file it shows all the two tests has started in browser stack and always latest one complete and previous one times out. Here is my code. Glad if anyone can help.
Pom File
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.dimaj</groupId>
<artifactId>zucchini-sample</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Zucchini Sample Project</name>
<description>A sample project that demonstrates how to use Zucchini against multiple web browsers</description>
<contributors>
<contributor>
<name>Dmitry Jerusalimsky</name>
<url>http://blog.dimaj.net</url>
</contributor>
</contributors>
<properties>
<cucumber.version>1.2.4</cucumber.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.comcast.zucchini/zucchini -->
<dependency>
<groupId>com.comcast.zucchini</groupId>
<artifactId>zucchini</artifactId>
<version>2.3.1</version>
</dependency>
<!-- <dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>2.46.0</version>
<scope>test</scope>
</dependency> -->
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>5.0.4</version>
<!--<exclusions>-->
<!--<exclusion>-->
<!--<groupId>com.google.guava</groupId>-->
<!--<artifactId>guava</artifactId>-->
<!--</exclusion>-->
<!--</exclusions>-->
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-junit</artifactId>
<version>1.2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-testng -->
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-testng</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- <parallel>classes</parallel> -->
<threadCount>2</threadCount>
<reuserForks>false</reuserForks>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Runner Class :
package net.dimaj.zucchini.tests;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.comcast.zucchini.AbstractZucchiniTest;
import com.comcast.zucchini.TestContext;
import com.comcast.zucchini.ZucchiniOutput;
import cucumber.api.CucumberOptions;
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import net.dimaj.zucchini.utils.Constants;
import org.openqa.selenium.remote.DesiredCapabilities;
@CucumberOptions(features = { "src/test/resources/StartPage.feature" }, glue = { "net.dimaj.zucchini.sample.glue" })
public class FirstZucchiniTest extends AbstractZucchiniTest {
String USERNAME = "<>";
String ACCESS_KEY = "<>";
String url = "https://" + USERNAME + ":" + ACCESS_KEY + "@hub.browserstack.com/wd/hub";
private TestContext createContext(String name, String device, String os) throws MalformedURLException {
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("device", device);
caps.setCapability("os_version", os);
caps.setCapability("deviceName", "Android Device");
caps.setCapability("build", "Android_Browser Stack Pharellel");
caps.setCapability("name", "Pharellel Testing");
caps.setCapability("app", "bs://dlslldlfll");
caps.setCapability("networkLogs", true);
AndroidDriver<MobileElement> driver = new AndroidDriver<MobileElement>(new java.net.URL(url), caps);
TestContext context = new TestContext(name);
context.set(Constants.CONTEXT_ANDROID, driver);
return context;
}
@Override
public List<TestContext> getTestContexts() {
List<TestContext> driverList = new ArrayList<TestContext>();
try {
driverList.add(createContext("Remote1", "Google Pixel", "7.1"));
driverList.add(createContext("Remote2", "Google Nexus 6", "6.0"));
}
catch (MalformedURLException e) {
throw new RuntimeException("Couldn't create driver", e);
}
return driverList;
}
@Before
public void setupTests(Scenario scenario) {
TestContext.getCurrent().set(Constants.CONTEXT_SCENARIO, scenario);
}
@Override
public void cleanup(TestContext out) {
AndroidDriver<MobileElement> driver = out.get(Constants.CONTEXT_ANDROID);
if (null != driver) {
driver.quit();
}
}
}
My step Definition class
package net.dimaj.zucchini.sample.glue;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import com.comcast.zucchini.TestContext;
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.When;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.pagefactory.AndroidBy;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.WithTimeout;
import io.appium.java_client.pagefactory.iOSFindBy;
import net.dimaj.zucchini.utils.Constants;
public class StartPageSteps{
AppiumDriver<MobileElement> androidDriver;
@AndroidFindBy(id = "intro_login")
@WithTimeout(time = 5, unit = TimeUnit.SECONDS)
private MobileElement logInButton;
public StartPageSteps(){
androidDriver = TestContext.getCurrent().get(Constants.CONTEXT_ANDROID);
}
@Before
public void setup(Scenario scenario) {
TestContext.getCurrent().set("scenario", scenario);
}
private By loginBtn = By.id("intro_login");
@Given("Sign Up is displayed")
public void sign_Up_is_displayed() {
androidDriver.findElement(loginBtn).isDisplayed();
}
@When("user taps Sign Up button")
public void user_taps_Sign_Up_button() {
//androidDriver.findElement(loginBtn).click();
assert(androidDriver.findElement(loginBtn).isDisplayed());
}
}
Here is my Log :
Session ID: ebed1cfaf948d20a2c715e39711b672e6feca130
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:214)
at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:166)
at org.openqa.selenium.remote.http.JsonHttpResponseCodec.reconstructValue(JsonHttpResponseCodec.java:40)
at org.openqa.selenium.remote.http.AbstractHttpResponseCodec.decode(AbstractHttpResponseCodec.java:82)
at org.openqa.selenium.remote.http.AbstractHttpResponseCodec.decode(AbstractHttpResponseCodec.java:45)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:164)
at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:89)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:586)
at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:46)
at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
at io.appium.java_client.HasSessionDetails.getSessionDetails(HasSessionDetails.java:38)
at io.appium.java_client.HasSessionDetails.getSessionDetail(HasSessionDetails.java:55)
at io.appium.java_client.HasSessionDetails.getPlatformName(HasSessionDetails.java:62)
at io.appium.java_client.DefaultGenericMobileDriver.toString(DefaultGenericMobileDriver.java:156)
at io.appium.java_client.AppiumDriver.toString(AppiumDriver.java:1)
at io.appium.java_client.android.AndroidDriver.toString(AndroidDriver.java:1)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractMap.toString(AbstractMap.java:559)
at com.comcast.zucchini.TestContext.toString(TestContext.java:107)
at com.comcast.zucchini.AbstractZucchiniTest.runParallel(AbstractZucchiniTest.java:181)
at com.comcast.zucchini.AbstractZucchiniTest.run(AbstractZucchiniTest.java:129)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:348)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305)
at org.testng.SuiteRunner.run(SuiteRunner.java:254)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:77)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:110)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:106)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
07:27:38.000 [Thread-1] WARN c.c.zucchini.ZucchiniShutdownHook - There are 0 features run
Results :
Failed tests: run(net.dimaj.zucchini.tests.FirstZucchiniTest): Session not started or terminated (WARNING: The server did not provide any stacktrace information)(..)
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
What happens if you change your
FirstZucchiniTest
to this:The main thing that was changed here was the handling of exception if AndroidDriver fails to initialize.
My thoughts here are such that your second driver fails to initialize and it is added to TestContext as
null
. Then, whenTestContext.toString()
is being called, it callstoString()
on everyObject
that has been added to TestContext and, if that fail, you end up with exceptions. Here's an example of what I mean: http://tpcg.io/EonKtSIn the updated response above, I am overriding definition of the
toString
function to avoid printing out contents of the current context. If you will still be failing, then I would look into browserstack.