弹簧导致WebDriver降低()'每次测试之后
我正在尝试使Spring Boot Selenium应用程序工作。我可以成功进行一项测试,但是当我进行多个测试时,第二个测试会抱怨:
会话ID为null。调用Quit()?
后使用WebDriver
查看源代码并放入断点后,春季似乎正在调用quit()
方法,用于webdriver
在第一个测试之后。
每次测试后如何让它不退出?我考虑过只是不使用页面类的依赖注入。
这是我的测试类:
@SpringBootTest
public class LoginTest {
@Autowired LoginPage loginPage;
@Test
public void shouldLogin() {
loginPage.login();
}
@Test
public void shouldLoginToAdminPage() {
loginPage.adminLogin();
}
}
我的登录页
:
@Component
public class LoginPage extends BasePage {
@FindBy(how = How.XPATH, using = "//gat-input[@formcontrolname = 'userName']//input")
private WebElement txtUserName;
@FindBy(how = How.XPATH, using = "//gat-input[@formcontrolname='password']//input")
private WebElement txtPassword;
@FindBy(how = How.XPATH, using = "//gat-button[@label='Login']/button")
private WebElement btnLogin;
protected void login(String username, String password) {
loadPage();
sendKeysWhenReady(txtUserName, username);
sendKeysWhenReady(txtPassword, password);
clickWhenReady(btnLogin);
}
public void adminLogin() {
login(properties.getAdminUsername(), properties.getAdminPassword());
}
public void login() {
login(properties.getRegularUsername(), properties.getRegularPassword());
}
@Override
public void verifyPageLoaded() {
waitTillElementIsReady(btnLogin, 5);
}
@Override
protected String getPath() {
return "/login";
}
}
basepage
:
public abstract class BasePage {
@Autowired private WebDriver driver;
@Autowired protected Properties properties;
@PostConstruct
public void initDriver() {
driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
PageFactory.initElements(driver, this);
}
public void loadPage() {
getDriver().get(getUrl());
verifyPageLoaded();
}
public String getUrl() {
return properties.getBaseUrl().concat(getPath());
}
// example "/login"
protected abstract String getPath();
public abstract void verifyPageLoaded();
public WebDriver getDriver() {
return driver;
}
protected void waitTillElementIsReady(WebElement webElement, int seconds) {
WebDriverWait wait = new WebDriverWait(driver, seconds);
wait.until(ExpectedConditions.visibilityOf(webElement));
}
protected void sendKeysWhenReady(WebElement webElement, String keys) {
waitTillElementIsReady(webElement, 5);
webElement.sendKeys(keys);
}
protected void clickWhenReady(WebElement webElement) {
waitTillElementIsReady(webElement, 3);
webElement.click();
}
}
配置类:
public class WebDriverLibrary {
@Bean
public WebDriver getChromeDriver() {
WebDriverManager.chromedriver().setup();
return new ChromeDriver();
}
}
和我的依赖项:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.seleniumhq.selenium:selenium-java:4.2.1'
implementation 'io.github.bonigarcia:webdrivermanager:5.2.0'
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.testng:testng:7.6.0'
testImplementation 'org.testcontainers:junit-jupiter:1.17.2'
testImplementation 'org.testcontainers:selenium:1.17.2'
}
I'm trying to get a Spring Boot Selenium app to work. I can get one test to run successfully, but when I run more than one test, the second test complains with:
Session ID is null. Using WebDriver after calling quit()?
After looking through the source code and putting in breakpoints, it looks like Spring is calling the quit()
method for WebDriver
after the first test.
How do I get it to not quit after each test? I've thought about just not using dependency injection for the page classes.
Here is my test class:
@SpringBootTest
public class LoginTest {
@Autowired LoginPage loginPage;
@Test
public void shouldLogin() {
loginPage.login();
}
@Test
public void shouldLoginToAdminPage() {
loginPage.adminLogin();
}
}
My LoginPage
:
@Component
public class LoginPage extends BasePage {
@FindBy(how = How.XPATH, using = "//gat-input[@formcontrolname = 'userName']//input")
private WebElement txtUserName;
@FindBy(how = How.XPATH, using = "//gat-input[@formcontrolname='password']//input")
private WebElement txtPassword;
@FindBy(how = How.XPATH, using = "//gat-button[@label='Login']/button")
private WebElement btnLogin;
protected void login(String username, String password) {
loadPage();
sendKeysWhenReady(txtUserName, username);
sendKeysWhenReady(txtPassword, password);
clickWhenReady(btnLogin);
}
public void adminLogin() {
login(properties.getAdminUsername(), properties.getAdminPassword());
}
public void login() {
login(properties.getRegularUsername(), properties.getRegularPassword());
}
@Override
public void verifyPageLoaded() {
waitTillElementIsReady(btnLogin, 5);
}
@Override
protected String getPath() {
return "/login";
}
}
The BasePage
:
public abstract class BasePage {
@Autowired private WebDriver driver;
@Autowired protected Properties properties;
@PostConstruct
public void initDriver() {
driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
PageFactory.initElements(driver, this);
}
public void loadPage() {
getDriver().get(getUrl());
verifyPageLoaded();
}
public String getUrl() {
return properties.getBaseUrl().concat(getPath());
}
// example "/login"
protected abstract String getPath();
public abstract void verifyPageLoaded();
public WebDriver getDriver() {
return driver;
}
protected void waitTillElementIsReady(WebElement webElement, int seconds) {
WebDriverWait wait = new WebDriverWait(driver, seconds);
wait.until(ExpectedConditions.visibilityOf(webElement));
}
protected void sendKeysWhenReady(WebElement webElement, String keys) {
waitTillElementIsReady(webElement, 5);
webElement.sendKeys(keys);
}
protected void clickWhenReady(WebElement webElement) {
waitTillElementIsReady(webElement, 3);
webElement.click();
}
}
The Config class:
public class WebDriverLibrary {
@Bean
public WebDriver getChromeDriver() {
WebDriverManager.chromedriver().setup();
return new ChromeDriver();
}
}
And my dependencies:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.seleniumhq.selenium:selenium-java:4.2.1'
implementation 'io.github.bonigarcia:webdrivermanager:5.2.0'
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.testng:testng:7.6.0'
testImplementation 'org.testcontainers:junit-jupiter:1.17.2'
testImplementation 'org.testcontainers:selenium:1.17.2'
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我发现有两种解决这个问题的方法。
但是,这一切都取决于Selenium Webdriver Java实施并不是真正的“春季”友好。您需要一个新的
WebDriver
,每个测试都需要在页面对象之间共享。没有很好的方法可以使用@Autowired
页面对象。因此,您可以使用依赖项注入,但是您必须在每个测试之前使用
@dirtiesContext
注释,每次测试都会创建并破坏webdriver
注射对象)。但是,这也可能非常昂贵,具体取决于每次测试的强度以及每次都将重新加载的上下文的大小。另一种方法是不要注入页面对象,而是在每个测试之前重新创建它们(junit:
@beforeach
,testng:@beforemethod
),WebDriver
对象作为每个构造函数参数,以便每个页面对象都可以共享WebDriver
。您还需要执行webdriver.quit()
在每个测试之后关闭过时的驱动程序(junit:@aftereach
,testng:@aftermethod )。
I found that there are two ways to address this.
However, it all comes down to the Selenium webdriver java implementation not really being "Spring" friendly. You need a new
WebDriver
for each test and it needs to be shared between page objects. There is no great way to do this with@Autowired
page objects.So you can use dependency injection, but you would have to use the
@DirtiesContext
annotation before each test, which would create and destroy theWebDriver
each time (along with all the other injected objects). However, it would also be potentially very expensive depending on how intense each test is and how big the context that is being reloaded every time would be.The other way is to not have the page objects injected, but to create them anew before each test (jUnit:
@BeforeEach
, TestNG:@BeforeMethod
), with theWebDriver
object as a constructor argument for each so that each page object can share theWebDriver
. You would also need to perform theWebDriver.quit()
after each test to shut down the stale driver (jUnit:@AfterEach
, TestNG:@AfterMethod
).我最近遇到了类似的问题。在方法中添加
@scope(configurableBeanfactory.scope_singleton)
spring注释,其中注入webdriver
bean,对我有帮助。https://github.com/spring-projects/spring-projects/spring-boot/issues/spring-boot/issues/ 7454
I faced a similar problem recently. Adding the
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
Spring annotation in method, which injectwebDriver
bean, helped me.https://github.com/spring-projects/spring-boot/issues/7454
Spring automatically calls
quit()
on your injected driver这使我能够使我的基础测试类能够在错误时拍摄屏幕截图。
我在调用
realquit()
的地方,您可以轻松地使驱动程序打开。Spring automatically calls
quit()
on your injected driver here. I was attempting to take screenshots whenever my tests failed, and finding the driver was already closed. I already had the need for a custom driver, so I fixed this with a no-opquit()
override.This allowed me to give my base test class the ability to snap screenshots on error.
Where I'm calling
realQuit()
, you could just as easily leave the driver open.