首页 > 解决方案 > 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());

  }
}

似乎我关于默认浏览器的设置未应用。其他设置(如屏幕截图)工作得很好。

标签: spring-bootseleniumselenium-webdriverjunit5selenium-jupiter

解决方案


根据我的研究,将浏览器添加到 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());

    }
}

请注意:

  1. 在我的示例中,我使用 VM 选项-Dprop.browsers.list=chrome,firefox来为测试提供多个浏览器。
  2. 应该为 SeleniumBaseTestEnvironment 的所有子类的每个方法放置注释@TestTemplate。(您可以创建自己的类级别注释来解决它)。
  3. 为了切换Webdriver实现,您可以为每个环境设置一个弹簧配置,该配置将提供适当的驱动程序列表。

推荐阅读