spring-boot - Selenium-Jupiter 通用 webdriver 设置未应用
问题描述
我想在我的 Spring Boot 项目中使用 Selenium-Jupiter,但我的要求是在运行时切换 WebDriver 实现 - 基于执行环境 - 对所有测试使用一个通用基类。
堆栈跟踪:
2020-09-17 23:17:47.196 INFO 14092 --- [ Test worker] d[....path....].SignupPageTest : Started SignupPageTest in 26.133 seconds (JVM running for 29.179)
2020-09-17 23:17:47.498 WARN 14092 --- [ Test worker] i.g.bonigarcia.seljup.SeleniumExtension : Driver handler for context id [engine:junit-jupiter]/[class:de,[....path....].SignupPageTest]/[method:verifyLogInPage(org.openqa.selenium.WebDriver)] not found
Failed to resolve parameter [org.openqa.selenium.WebDriver genDriver] in method [public void de.[....path....].SignupPageTest.verifyLogInPage(org.openqa.selenium.WebDriver) throws java.lang.Exception]: org/glassfish/hk2/api/MultiException
org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [org.openqa.selenium.WebDriver genDriver] in method [public void de.[....path....].SignupPageTest.verifyLogInPage(org.openqa.selenium.WebDriver) throws java.lang.Exception]: org/glassfish/hk2/api/MultiException
at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameter(ExecutableInvoker.java:239)
at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameters(ExecutableInvoker.java:183)
at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameters(ExecutableInvoker.java:144)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:96)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy5.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: java.lang.NoClassDefFoundError: org/glassfish/hk2/api/MultiException
at io.github.bonigarcia.seljup.DockerService.<init>(DockerService.java:79)
at io.github.bonigarcia.seljup.SeleniumExtension.initHandlerForDocker(SeleniumExtension.java:381)
at io.github.bonigarcia.seljup.SeleniumExtension.getDriverHandler(SeleniumExtension.java:242)
at io.github.bonigarcia.seljup.SeleniumExtension.resolveParameter(SeleniumExtension.java:220)
at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameter(ExecutableInvoker.java:216)
... 73 more
Caused by: java.lang.ClassNotFoundException: org.glassfish.hk2.api.MultiException
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 78 more
de.[....path....].SignupPageTest > verifyLogInPage(WebDriver) FAILED
org.junit.jupiter.api.extension.ParameterResolutionException at ExecutableInvoker.java:239
Caused by: java.lang.NoClassDefFoundError at DockerService.java:79
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:602
提前使用 chrome-driver 一切正常,但不适用于通用 webdriver。
我使用 Java14 并为 selenium 测试创建了一个额外的源集,称为“endToEndTest”
这是与gradle.build相关的所有内容:
sourceCompatibility = 14
sourceSets {
endToEndTest {
java.srcDir('src/end-to-end-test/java')
resources.srcDir file('src/end-to-end-tests/resources')
compileClasspath += sourceSets.main.output + configurations.testRuntime
runtimeClasspath += output + compileClasspath
}
}
configurations {
endToEndTestImplementation.extendsFrom testImplementation
endToEndTestRuntimeOnly.extendsFrom testRuntimeOnly
}
task endToEndTest(type: Test) {
testClassesDirs = sourceSets.endToEndTest.output.classesDirs
classpath = sourceSets.endToEndTest.runtimeClasspath
useJUnitPlatform ()
}
endToEndTestImplementation('io.github.bonigarcia:selenium-jupiter:3.3.5')
我有一个基类,所有其他测试类都应该从该基类扩展。它负责启动 Web 环境等。
基类
@ExtendWith({SpringExtension.class})
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SeleniumBaseTestEnvironment {
@RegisterExtension
static SeleniumExtension seleniumJupiter = new SeleniumExtension();
@LocalServerPort
protected int serverPort;
@BeforeAll
public static void beforeAll() {
//both seems to have no impact
seleniumJupiter.getConfig().setDefaultBrowser("chrome");
seleniumJupiter.addBrowsers(BrowserBuilder.chrome().build());
}
protected String getUrl(String address) {
return "http://localhost:" + serverPort + address;
}
}
Testclass 如果我用 ChromeDriver 替换 WebDriver 就可以了。但我需要通用驱动程序。
public class SignupPageTest extends SeleniumBaseTestEnvironment {
@Test
public void verifyLogInPage(WebDriver genDriver) throws Exception {
genDriver.get(getUrl("/"));
List<WebElement> cardTitleList = genDriver.findElements(By.className("card-title"));
List<WebElement> navbar = genDriver.findElements(By.className("navbar-toggler collapsed"));
assertEquals(cardTitleList.get(0).getText(), "Login");
assertTrue(navbar.isEmpty());
}
}
似乎我关于默认浏览器的设置未应用。其他设置(如屏幕截图)工作得很好。
解决方案
根据我的研究,将浏览器添加到 Selenium Extension 仅适用于 Selenium Jupiter 中的测试模板功能。
因此,使用以下代码的测试模板应该可以工作:
@ExtendWith({SpringExtension.class})
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SeleniumBaseTestEnvironment {
@RegisterExtension
static SeleniumExtension seleniumJupiter = new SeleniumExtension();
@LocalServerPort
protected int serverPort;
@BeforeAll
public static void beforeAll() {
String browsersList = System.getProperty("prop.browsers.list");
List<String> browsers = Arrays.asList(browsersList.split(","));
if (browsers.contains("chrome")) {
seleniumJupiter.addBrowsers(BrowserBuilder.chrome().build());
}
if (browsers.contains("firefox")) {
seleniumJupiter.addBrowsers(BrowserBuilder.firefox().build());
}
//----// All browsers you need
}
protected String getUrl(String address) {
return "http://localhost:" + serverPort + address;
}
public class SignupPageTest extends SeleniumBaseTestEnvironment {
@TestTemplate
public void verifyLogInPage(WebDriver genDriver) throws Exception {
genDriver.get(getUrl("/"));
List<WebElement> cardTitleList = genDriver.findElements(By.className("card-title"));
List<WebElement> navbar = genDriver.findElements(By.className("navbar-toggler collapsed"));
assertEquals(cardTitleList.get(0).getText(), "Login");
assertTrue(navbar.isEmpty());
}
}
请注意:
- 在我的示例中,我使用 VM 选项
-Dprop.browsers.list=chrome,firefox
来为测试提供多个浏览器。 - 应该为 SeleniumBaseTestEnvironment 的所有子类的每个方法放置注释
@TestTemplate
。(您可以创建自己的类级别注释来解决它)。 - 为了切换
Webdriver
实现,您可以为每个环境设置一个弹簧配置,该配置将提供适当的驱动程序列表。
推荐阅读
- angular6 - 相对路由在 canActivate 防护中不起作用
- javascript - React - 如何使用本地 .json 文件中的数据根据另一个选择菜单的值填充一个选择菜单
- xml - 使用样式表将新元素添加到导入的 xsl
- python - Asyncio 属性错误,pyinstaller 包
- excel - Excel VBA图表 - 如果包含“括号”,将图表的标签设置为红色?
- objective-c - 请求关联构建器开始收集时的授权错误
- c# - 我可以在 xaml 代码中禁用 WPF 组合框的第一项吗?
- c# - 如何查看数据集函数的性能利用率
- python - 如何在不使用 reverse=True 参数的情况下以相反的顺序对字符串列表进行排序?
- javascript - 将 YES/NO 转换为 true/false 的更优雅的方法