【问题标题】:java.lang.StackOverflowError when running class as TestNG Test in Selenium在 Selenium 中将类作为 TestNG 测试运行时出现 java.lang.StackOverflowError
【发布时间】:2021-09-15 04:22:23
【问题描述】:

这是一个演示项目,使用页面对象模式和数据驱动框架来实现。

在继承之下,使用了构造函数的概念。

config.prpoerties 文件包含用户名、密码、url 和浏览器。

基类

package com.crm.qa.base;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

import com.crm.qa.utilities.TestUtil;

public class TestBase {
    
    public static Properties prop;
    public static WebDriver driver;
    
    public TestBase() {
    
        //import variables from Config.properties file
        try {
            prop=new Properties();
    
            FileInputStream fis=new FileInputStream(System.getProperty("user.dir")+"/src/main/java/com/crm/qa/configuration/config.properties");
    
                prop.load(fis);         
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }   
    
    public static void  initialization()
    {
        String browser= prop.getProperty("browser");
        
        if(browser.equalsIgnoreCase("firefox"))
        {
            System.setProperty("webdriver.gecko.driver", "./Drivers/geckodriver.exe");
            FirefoxOptions firefoxOptions = new FirefoxOptions();
            firefoxOptions.setCapability("marionette", true);
            driver = new FirefoxDriver(firefoxOptions);     
        }

        if(browser.equalsIgnoreCase("chrome"))
        {
            System.setProperty("webdriver.chrome.driver", "./Drivers/chromedriver.exe");
            driver=new ChromeDriver();
        }
    
        driver.manage().window().maximize();
        driver.manage().deleteAllCookies();
        driver.manage().timeouts().pageLoadTimeout(TestUtil.PAGE_LOAD_TIMEOUT, TimeUnit.SECONDS); 
        driver.manage().timeouts().pageLoadTimeout(TestUtil.IMPLICIT_WAIT, TimeUnit.SECONDS); 
        driver.get(prop.getProperty("baseURL"));
    }               
}

登录页面对象类

package com.crm.qa.pages;

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

import com.crm.qa.base.TestBase;

public class LoginPageCRM extends TestBase {
    
    
    //PageFactory
    @FindBy(name="username")
    WebElement username;
    
    
    @FindBy(name="password")
    WebElement password;
    
    @FindBy(xpath = "//input[@type='submit']")
    WebElement loginBtn;    
    
    @FindBy(xpath= "//a[contains(text(),'Sign Up')]")
    WebElement signUP;
    
    @FindBy(xpath="//img[contains(@class,'img-responsive')]")
    WebElement crmLogo;
    
    //to initialize page objects
    
    public LoginPageCRM()
    {
        PageFactory.initElements(driver, LoginPageCRM.class );
    }
    
    
    //Actions
    //1. verify title of page
    public String validateLoginPageTitle()
    {
        return driver.getTitle();
        
    }
    
    //2. Validate crm image
    public boolean validateCRMLogo()
    {
        return crmLogo.isDisplayed();
    }
    
    //3. Login
    public HomePageCRM login(String uname, String pwd)  
    {
        username.sendKeys(uname);
        password.sendKeys(pwd);
        loginBtn.click();
        
        return new HomePageCRM();
    }

}

package com.crm.qa.testcases;

import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import com.crm.qa.base.TestBase;
import com.crm.qa.pages.HomePageCRM;
import com.crm.qa.pages.LoginPageCRM;


public class LoginTest extends TestBase{
    
    public LoginTest()
    {
        super(); 
    }
    
    LoginPageCRM loginPage;
    public HomePageCRM homePageCRM;
    
    @BeforeTest
    public void setUP()
    {
    initialization();
    loginPage=new LoginPageCRM();
    }
    
    
    @Test(priority=1)
    public void LoginPageTitleTest()
    {
        String pageTitle= loginPage.validateLoginPageTitle();
        Assert.assertEquals(pageTitle,"CRMPRO  - CRM software for customer relationship management, sales, and support.");
        
    }
    
    @Test(priority=2)
    public void CRMLogoTest()
    {
        Assert.assertEquals(loginPage.validateCRMLogo(), true);
    }
    
    @Test(priority=3)
    public  void loginPageTest()
    {
        homePageCRM= loginPage.login(prop.getProperty("username"), prop.getProperty("password"));
    }
    
    
    @AfterTest
    public void tearDown()
    {
    driver.quit();      
    }

}

现在,当我将 LoginTest 类作为 TestNG 测试运行时,控制台中出现如下错误-->

com.crm.qa.testcases.LoginTest#setUP


Exception

java.lang.StackOverflowError
    at java.base/java.util.stream.StreamOpFlag.fromCharacteristics(StreamOpFlag.java:733)
    at java.base/java.util.stream.StreamSupport.stream(StreamSupport.java:70)
    at java.base/java.util.Arrays.stream(Arrays.java:5446)
    at java.base/java.util.Arrays.stream(Arrays.java:5427)
    at java.base/java.lang.Class.methodToString(Class.java:3579)
    at java.base/java.lang.Class.getConstructor0(Class.java:3508)
    at java.base/java.lang.Class.getConstructor(Class.java:2244)
    at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:128)
    at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:64)
    at com.crm.qa.pages.LoginPageCRM.<init>(LoginPageCRM.java:33)
    at jdk.internal.reflect.GeneratedConstructorAccessor9.newInstance(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    at java.base/java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)
    at java.base/jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:350)
    at java.base/java.lang.Class.newInstance(Class.java:645)
    at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:131)
    at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:64)
    at com.crm.qa.pages.LoginPageCRM.<init>(LoginPageCRM.java:33)
    at jdk.internal.reflect.GeneratedConstructorAccessor9.newInstance(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    at java.base/java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)
    at java.base/jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:350)
    at java.base/java.lang.Class.newInstance(Class.java:645)
    at org.openqa.selenium.support.PageFactory.instantiatePage(PageFactory.java:131)
    at org.openqa.selenium.support.PageFactory.initElements(PageFactory.java:64)
    at com.crm.qa.pages.LoginPageCRM.<init>(LoginPageCRM.java:33)
    at jdk.internal.reflect.GeneratedConstructorAccessor9.newInstance(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)

 

 ........

我的 Eclipse 版本: 版本:2021-03 (4.19.0) 版本号:20210312-0638

eclipse.ini 文件

-startup
plugins/org.eclipse.equinox.launcher_1.6.100.v20201223-0822.jar
--launcher.library
C:\Users\JACOB\.p2\pool\plugins\org.eclipse.equinox.launcher.win32.win32.x86_64_1.2.100.v20210209-1541
-product
org.eclipse.epp.package.java.product
-showsplash
C:\Users\JACOB\.p2\pool\plugins\org.eclipse.epp.package.common_4.19.0.20210311-1200
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vm
C:/Program Files/Java/jdk-15.0.1/bin/javaw.exe
-vmargs
-Dosgi.requiredJavaVersion=11
-Dosgi.instance.area.default=@user.home/eclipse-workspace
-Dsun.java.command=Eclipse
-XX:+UseG1GC
-XX:+UseStringDeduplication
--add-modules=ALL-SYSTEM
-Dosgi.requiredJavaVersion=11
-Dosgi.dataAreaRequiresExplicitInit=true
-Dorg.eclipse.swt.graphics.Resource.reportNonDisposed=true
-Xms256m
-Xmx2048m
--add-modules=ALL-SYSTEM
-Declipse.p2.max.threads=10
-Doomph.update.url=http://download.eclipse.org/oomph/updates/milestone/latest
-Doomph.redirection.index.redirection=index:/->http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/

【问题讨论】:

    标签: java eclipse selenium selenium-webdriver testng


    【解决方案1】:

    我曾经遇到过这个错误。如何解决它,改变它

    PageFactory.initElements(driver, LoginPageCRM.class );
    

    PageFactory.initElements(driver, this);
    

    【讨论】:

    • 解释为什么当前代码 PageFactory.initElements(driver, LoginPageCRM.class) 失败 -> initElements 尝试通过调用它的构造函数来创建 LoginPageCRM 的对象。因为LoginPageCRM 的构造函数包含PageFactory.initElements(driver, LoginPageCRM.class)。所以这个过程无限次重复导致 Stackoverflow 错误。这是问题的根本原因。
    • 那么PageFactory.initElements(driver, this)会返回当前类的对象吗?
    【解决方案2】:

    PageFactory.initElements(driver, LoginPageCRM.class) 导致StackOverflowError 是因为initElements 试图通过调用它的构造函数来创建LoginPageCRM 的对象。并且由于LoginPageCRM 的构造函数包含PageFactory.initElements(driver, LoginPageCRM.class),这个过程被无限次重复导致StackOverflowError。这是问题的根本原因。

    由于我对硒不太熟悉,我假设@lucasnguyen17 的回答解释了如何解决它。但我建议在将 this 传递给构造函数中的该方法之前进行一些更改。


    注意:下面提到的问题可能不会在您的情况下导致问题,因为在构造函数中没有使用 this 的其他操作。但以下内容可以作为一般准则/最佳实践来遵循


    如果this 引用在构造过程中“转义”,则认为对象构造不正确。即只有在构造函数完全执行时才说对象是正确构造的。如果您按如下方式修复代码,则您将 构造不正确的对象 传递给 initElements 方法。这可以被认为类似于在施工完成之前将房屋出租给某人。因此,这是一种错误的做法,应该这样做,因为它可能会导致意外结果,因为您可能不知道您正在调用的方法将如何处理您传递的对象。

    public LoginPageCRM()
    {
        // The object is not fully constructed at this point
        PageFactory.initElements(driver, this);
    }
    

    所以我建议进行以下重构:

    LoginPageCRM 中只需创建一个默认构造函数,其中不包含任何代码。 (如果类中没有其他构造函数,Java 实际上会创建一个)。然后创建一个可以执行PageFactory.initElements(driver, this)的方法:

    public LoginPageCRM()
    {
    }
    
    public void init() {
        PageFactory.initElements(driver, this);
    }
    

    然后在LoginTest类中,构造LoginPageCRM对象后,调用新的init方法,这样就可以确保传递的是正确构造的对象。

    @BeforeTest
    public void setUP() {
        initialization();
        loginPage = new LoginPageCRM();
        loginPage.init();
    }
    

    【讨论】:

    • 谢谢@Gautham M,试试看
    猜你喜欢
    • 2016-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多