0

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
Chinthaka Devinda
  • 997
  • 5
  • 16
  • 36

1 Answers1

0

What happens if you change your FirstZucchiniTest to this:

package net.dimaj.zucchini.tests;

import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import com.comcast.zucchini.AbstractZucchiniTest;
import com.comcast.zucchini.TestContext;
import cucumber.api.CucumberOptions;
import cucumber.api.Scenario;
import cucumber.api.java.Before;
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 = "<username>";
    String ACCESS_KEY = "<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://48da5beeef475d0c1716b7d2eaad3e18d2e8ebf8");
      caps.setCapability("networkLogs", true);

      AndroidDriver<MobileElement> driver = new AndroidDriver<MobileElement>(new java.net.URL(url), caps);
      TestContext context = new TestContext(name) {
         @Override
         public String toString() {
           return this.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();
        }
    }

}

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, when TestContext.toString() is being called, it calls toString() on every Object 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/EonKtS

In 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.

dimaj
  • 3
  • 2
  • 4
  • Hello, @dimaj thank you for your reply. Yeah you are correct and I have updated it in the post and also I changed to mobile element instead of web element. I am still getting an error. Attached the log file – Chinthaka Devinda Apr 24 '19 at 01:56
  • With a single driver, it works fine. When I add the second driver not worked and throw me that error. – Chinthaka Devinda Apr 24 '19 at 02:10
  • Well, this output seems a bit better than the previous. No more NPEs... Please try removing the `junit` dependency. Zucchini depends on `testng` and it is including `cucumber-testng` as one of its dependencies. Also, please downgrade cucumber version to 1.2.4. Let's match it as closely as possible to my sample and then start changing it 1 element at a time. – dimaj Apr 24 '19 at 05:10
  • Ok great let me try – Chinthaka Devinda Apr 24 '19 at 05:42
  • Also, one thing that concerns me is your try/catch block that is creating your `AdndroidDriver` objects. You are swallowing an exception and moving forward. I wonder if that is the reason behind the failure. What will happen if you were to replace `e.printStackTrace();` with `throw new RuntimeException("Failed to create driver", e);` – dimaj Apr 24 '19 at 05:57
  • I have just updated things as you said but still getting the same issue. The single test works fine. Only if I add 2nd one it starts to fail. – Chinthaka Devinda Apr 24 '19 at 06:19
  • I have also tried with changing to latest version still I am getting the same issue not sure what exactly went wrong. – Chinthaka Devinda Apr 24 '19 at 22:53
  • You've tried it with the code I've posted in the answer? (it's been updated since we started talking here). Do both targets run individually? – dimaj Apr 25 '19 at 17:04
  • Hi, @dimaj yeah, I have just tried it sorry I didn't see it before. But still the same issue. I have just updated my question. – Chinthaka Devinda Apr 25 '19 at 23:35
  • it should not be the same as we have overwrote the `toString` function and the function that was defined in `TestContext` should not have been executed – dimaj Apr 26 '19 at 04:06