java.lang.ExceptionInInitializerError 与 AppiumFieldDecorator - JAVA、黄瓜、Appium

java.lang.ExceptionInInitializerError with AppiumFieldDecorator - JAVA, Cucumber, Appium

大家好!
我正在尝试使用 Cucumber & Appium 为移动应用程序设置一个自动化项目(iOS 和 Android 两者)。
我计划在 JAVA 中编写项目,并使用 Gradle 来实现所需的依赖项。

所以我写了一个小项目,由于某种原因它一直失败并出现以下错误:

java.lang.ExceptionInInitializerError

调用PageFactory.initElements(new AppiumFieldDecorator(driver), this);

时出现异常 这就是我实现页面对象的方式 class:

public class OnboardingPageObjects {

    public OnboardingPageObjects(AppiumDriver driver) {
        PageFactory.initElements(new AppiumFieldDecorator(driver), this);
    }

    @AndroidFindBy(id = "com.bupp.wood_spoon_chef.staging:id/orangeBtnBackground")
    public WebElement getStartedButton;
}

这是测试 class,它在 @Before 挂钩中失败:

public class FeedSteps {

    public Capabilities cap;
    public OnboardingPageObjects onboardingPageObjects;

    @Before()
    public void setup() throws MalformedURLException {
        cap = new Capabilities();
        cap.preparation("4723", Platform.ANDROID);
        onboardingPageObjects = new OnboardingPageObjects(cap.getDriver());
    }
    ...
}

这是我初始化AppiumDriver的class(目前只有Android驱动,iOS驱动没有使用):

public class Capabilities {

    private AppiumDriver driver = null;
    public DesiredCapabilities capabilities = new DesiredCapabilities();

    public void preparation(String port, Platform platform) throws MalformedURLException {
        if (platform == Platform.IOS) {
            capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
            //capabilities.setCapability(MobileCapabilityType.UDID, "emulator-5554");
            capabilities.setCapability(IOSMobileCapabilityType.BUNDLE_ID, "");
            capabilities.setCapability("instrumentedApp", true);
            driver = new IOSDriver(new URL("http://localhost:"+port+"/wd/hub"), capabilities);
            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        } else {
            capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
            capabilities.setCapability(MobileCapabilityType.UDID, "emulator-5554");
            capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.bupp.wood_spoon_chef.staging");
            capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, "com.bupp.wood_spoon_chef.presentation.features.splash.SplashActivity");
            driver = new AndroidDriver(new URL("http://localhost:"+port+"/wd/hub"), capabilities);
            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        }
    }

    public AppiumDriver getDriver() {
        return driver;
    }

    public void stopDriver() {
        driver.quit();
    }
}

如果我更改相同的代码:

  1. new AppiumFieldDecorator(driver) 而不是这样做:PageFactory.initElements(driver, this);
  2. @AndroidFindBy更改为@FindBy

这是我得到的错误:

Step failed
java.lang.ExceptionInInitializerError
    at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:53)
    at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:33)
    at io.appium.java_client.pagefactory.AppiumFieldDecorator.proxyForAnElement(AppiumFieldDecorator.java:209)
    at io.appium.java_client.pagefactory.AppiumFieldDecorator.access[=16=]0(AppiumFieldDecorator.java:61)
    at io.appium.java_client.pagefactory.AppiumFieldDecorator.proxyForLocator(AppiumFieldDecorator.java:100)
    at org.openqa.selenium.support.pagefactory.DefaultFieldDecorator.decorate(DefaultFieldDecorator.java:63)
    at io.appium.java_client.pagefactory.AppiumFieldDecorator.decorate(AppiumFieldDecorator.java:147)
    at org.openqa.selenium.support.PageFactory.proxyFields(PageFactory.java:111)
    at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:103)
    at com.eatwoodspoon.homechefs.pages.onboarding.OnboardingPageObjects.<init>(OnboardingPageObjects.java:12)
    at com.eatwoodspoon.homechefs.stepsdefs.feed.FeedSteps.setup(FeedSteps.java:22)
Caused by: net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InaccessibleObjectException-->Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @6073f712
    at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:464)
    at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:339)
    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.apply(AbstractClassGenerator.java:96)
    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.apply(AbstractClassGenerator.java:94)
    at net.sf.cglib.core.internal.LoadingCache.call(LoadingCache.java:54)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
    at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119)
    at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294)
    at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:221)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:174)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:153)
    at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:73)
    at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:53)
    at io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy(ProxyFactory.java:33)
    at io.appium.java_client.pagefactory.AppiumFieldDecorator.proxyForAnElement(AppiumFieldDecorator.java:209)
    at io.appium.java_client.pagefactory.AppiumFieldDecorator.access[=16=]0(AppiumFieldDecorator.java:61)
    at io.appium.java_client.pagefactory.AppiumFieldDecorator.proxyForLocator(AppiumFieldDecorator.java:100)
    at org.openqa.selenium.support.pagefactory.DefaultFieldDecorator.decorate(DefaultFieldDecorator.java:63)
    at io.appium.java_client.pagefactory.AppiumFieldDecorator.decorate(AppiumFieldDecorator.java:147)
    at org.openqa.selenium.support.PageFactory.proxyFields(PageFactory.java:111)
    at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:103)
    at com.eatwoodspoon.homechefs.pages.onboarding.OnboardingPageObjects.<init>(OnboardingPageObjects.java:12)
    at com.eatwoodspoon.homechefs.stepsdefs.feed.FeedSteps.setup(FeedSteps.java:22)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at io.cucumber.java.Invoker.doInvoke(Invoker.java:66)
    at io.cucumber.java.Invoker.invoke(Invoker.java:24)
    at io.cucumber.java.AbstractGlueDefinition.invokeMethod(AbstractGlueDefinition.java:47)
    at io.cucumber.java.JavaHookDefinition.execute(JavaHookDefinition.java:64)
    at io.cucumber.core.runner.CoreHookDefinition.execute(CoreHookDefinition.java:46)
    at io.cucumber.core.runner.HookDefinitionMatch.runStep(HookDefinitionMatch.java:21)
    at io.cucumber.core.runner.ExecutionMode.execute(ExecutionMode.java:10)
    at io.cucumber.core.runner.TestStep.executeStep(TestStep.java:85)
    at io.cucumber.core.runner.TestStep.run(TestStep.java:57)
    at io.cucumber.core.runner.TestCase.run(TestCase.java:78)
    at io.cucumber.core.runner.Runner.runPickle(Runner.java:75)
    at io.cucumber.core.runtime.Runtime.lambda$executePickle(Runtime.java:128)
    at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase(CucumberExecutionContext.java:129)
    at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:23)
    at io.cucumber.core.runtime.CucumberExecutionContext.runTestCase(CucumberExecutionContext.java:129)
    at io.cucumber.core.runtime.Runtime.lambda$executePickle(Runtime.java:128)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at io.cucumber.core.runtime.Runtime$SameThreadExecutorService.execute(Runtime.java:249)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:123)
    at io.cucumber.core.runtime.Runtime.lambda$runFeatures(Runtime.java:110)
    at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:197)
    at java.base/java.util.stream.SliceOps.accept(SliceOps.java:200)
    at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1602)
    at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
    at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at io.cucumber.core.runtime.Runtime.runFeatures(Runtime.java:111)
    at io.cucumber.core.runtime.Runtime.lambda$run[=16=](Runtime.java:82)
    at io.cucumber.core.runtime.Runtime.execute(Runtime.java:94)
    at io.cucumber.core.runtime.Runtime.run(Runtime.java:80)
    at io.cucumber.core.cli.Main.run(Main.java:87)
    at io.cucumber.core.cli.Main.main(Main.java:30)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @6073f712
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
    at net.sf.cglib.core.ReflectUtils.run(ReflectUtils.java:61)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
    at net.sf.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:52)
    at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:243)
    at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:332)
    ... 64 more

这是 Gradle 构建依赖项:

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
    implementation 'io.appium:java-client:8.0.0'
    implementation 'org.seleniumhq.selenium:selenium-java:4.1.4'
    testImplementation group: 'org.testng', name: 'testng', version: '7.6.0'
    implementation 'io.cucumber:cucumber-java:7.3.3'
    implementation group: 'io.cucumber', name: 'cucumber-testng', version: '7.3.4'
}

请帮忙,我不知道该怎么办!

好的,所以我找到了问题和解决方案!


问题出在运行器配置上。
出于某种原因,如果我们在 Cucumber 的 @Before 钩子中初始化页面对象,它会失败,但如果我们在 TestNG 的 @BeforeClass 钩子或 JUnit 的 @Before 钩子中做同样的事情,它就会完美地工作!

解决方法:
我更改了跑步者的配置。
我没有直接 运行 功能文件,而是在 TestRunner class 中使用了 @CucumberOptions。 这是我的 TestRunner class,后面是这篇文章:https://www.lambdatest.com/support/docs/running-cucumber-scripts-with-testng-and-selenium/

package com.eatwoodspoon.homechefs.infra;

import com.eatwoodspoon.homechefs.infra.setups.DriverCapabilities;
import io.cucumber.testng.CucumberOptions;
import io.cucumber.testng.FeatureWrapper;
import io.cucumber.testng.PickleWrapper;
import io.cucumber.testng.TestNGCucumberRunner;
import org.testng.annotations.*;

import java.net.MalformedURLException;

@CucumberOptions(features = {"src/test/resources/features"},
        glue = {"com/eatwoodspoon/homechefs/stepsDefinitios"},
        plugin = {
        "pretty",
        "html:target/cucumber-reports/cucumber-pretty",
        "json:target/cucumber-reports/CucumberTestReport.json",
        "rerun:target/cucumber-reports/rerun.txt",
        "json:target/cucumber-reports/CucumberTestReport.json"
        }
)
public class TestRunner {

    private TestNGCucumberRunner testNGCucumberRunner;

    public DriverCapabilities cap;
    public static HomeChefApp homeChefApp;

    @BeforeClass(alwaysRun = true)
    public void setUpCucumber() {
        testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
    }

    @BeforeMethod(alwaysRun = true)
    public void setUpClass() throws MalformedURLException {
        cap = new DriverCapabilities();
        cap.preparation("4723", Platform.ANDROID);
        homeChefApp = new HomeChefApp(cap.getDriver());
    }

    @Test(groups = "cucumber", description = "Runs Cucumber Feature", dataProvider = "features")
    public void feature(PickleWrapper pickle, FeatureWrapper cucumberFeature) {
        testNGCucumberRunner.runScenario(pickle.getPickle());
    }

    @DataProvider
    public Object[][] features() {
        return testNGCucumberRunner.provideScenarios();
    }

    @AfterClass(alwaysRun = true)
    public void tearDownClass() {
        testNGCucumberRunner.finish();
        cap.stopDriver();
    }
}