简体   繁体   English

Zucchini Concurrent黄瓜测试Android Appium示例

[英]Zucchini Concurrent cucumber testing Android Appium Example

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. 我目前正在研究Runner类的黄瓜自动化并行执行,我遇到了这个很好的框架http://comcast.github.io/zucchini/ ,我正面临着并行运行AndroidDriver测试用例的一些问题。 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. 当我使用via pom文件运行我的代码时,它显示所有两个测试都已经在浏览器堆栈中启动,并且总是最新的一个完成,之前的一次。 Here is my code. 这是我的代码。 Glad if anyone can help. 很高兴,如果有人可以帮助。

Pom File Pom文件

<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: 如果您将FirstZucchiniTest更改FirstZucchiniTest会发生什么:

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. 这里改变的主要是AndroidDriver无法初始化时处理异常。

My thoughts here are such that your second driver fails to initialize and it is added to TestContext as null . 我的想法是这样的,你的第二个驱动程序无法初始化,它被添加到TestContext为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. 然后,当调用TestContext.toString()时,它会在已添加到TestContext的每个Object上调用toString() ,如果失败,则最终会出现异常。 Here's an example of what I mean: http://tpcg.io/EonKtS 这是我的意思的一个例子: 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. 在上面更新的响应中,我重写了toString函数的定义,以避免打印出当前上下文的内容。 If you will still be failing, then I would look into browserstack. 如果你仍然会失败,那么我会调查一下browserstack。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM