Hey all!
I’m trying to set up an automation project using Cucumber & Appium for Mobile apps (iOS and Android both).
I plan to write the project in JAVA and I use Gradle for implementing the desired dependencies.
So I wrote a small project and for some reason it keeps failing with the following error:
java.lang.ExceptionInInitializerError
The exception occurs when I’m calling PageFactory.initElements(new AppiumFieldDecorator(driver), this);
This is how I implemented the page object 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; }
This is the tests class where it fails within the @Before
hook:
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()); } ... }
This is the class where I initialize the AppiumDriver
(currently only AndroidDriver, iOS driver is not in use):
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(); } }
The same code works if I change:
- The
new AppiumFieldDecorator(driver)
and instead doing this:PageFactory.initElements(driver, this);
- Change
@AndroidFindBy
to@FindBy
This is the error I get:
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$000(AppiumFieldDecorator.java:61) at io.appium.java_client.pagefactory.AppiumFieldDecorator$1.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$3.apply(AbstractClassGenerator.java:96) at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94) at net.sf.cglib.core.internal.LoadingCache$2.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$000(AppiumFieldDecorator.java:61) at io.appium.java_client.pagefactory.AppiumFieldDecorator$1.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$1.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$6(Runtime.java:128) at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase$5(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$7(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$3(Runtime.java:110) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.SliceOps$1$1.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$0(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$1.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
This is the Gradle build dependencies:
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' }
Please help, I don’t know what to do!
Advertisement
Answer
OK, so I found the problem and a solution!
The problem was with the runner configuration.
For some reason if we initialize the page objects inside the @Before
hook of Cucumber it fails but if we do the same within the @BeforeClass
hook of TestNG or @Before
hook of JUnit it worked flawlessly!
The solution:
I changed the configuration of the runner.
Instead of running the feature file directly, I used @CucumberOptions
within a TestRunner class.
Here is my TestRunner class followed by this article: 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(); } }