• Selenium Video Tutorials

Selenium Grid - 自定义节点



Selenium Grid 4 的最新版本是在没有利用 Selenium Grid 旧版本代码库的情况下开发的。此最新版本的 Selenium Grid 4 版本具有一些高级功能,例如自定义节点。

最新版本的 Selenium Grid 允许在三种不同的 Selenium Grid 模式下触发测试执行。它们被称为独立模式、集线器和节点模式以及分布式模式。

Selenium Grid 中的节点自定义

在使用 Selenium Grid 在不同浏览器及其平台、设备上执行并行测试或跨浏览器测试时,我们可能需要根据需求自定义节点。

在执行会话开始之前,我们可能需要添加一些先决条件步骤,或者在会话完成后执行任何整理活动。要执行节点自定义,需要执行以下步骤:

  • 设计一个类,该类将扩展 -

org.openqa.selenium.grid.node.Node.
  • 在新建的类中追加一个静态方法(工厂方法),该方法应具有以下签名:public static Node created(Config config)。此处,Node 与 org.openqa.selenium.grid.node.Node 类型相同,Config 与 - 类型相同。

org.openqa.selenium.grid.config.Config.
  • 在工厂方法内部,应添加新类的实现逻辑。

  • 要将新开发的实现合并到集线器中,请启动节点并将前一个的完全限定类名发送到参数:–node-implementation。

使用 Uber Jar 进行节点自定义

使用 uber jar 实现节点自定义的步骤如下所列:

  • 在系统中安装 Java(版本高于 8),并使用命令检查它是否存在:java -version。如果安装已成功完成,则将显示已安装的 Java 版本。

  • 在系统中安装 Maven,并使用命令检查它是否存在:mvn -version。如果安装已成功完成,则将显示已安装的 Maven 版本。

  • 安装任何 IDE,如 Eclipse、IntelliJ 等。

  • 从链接将 Selenium Grid 依赖项添加到 pom.xml 中:

    https://mvnrepository.com/artifact/.

  • 从链接将 Apache Maven Shade Plugin 添加到 pom.xml 中:

    https://mvnrepository.com/artifact/.

  • 将自定义节点附加到当前项目。

  • 构建 uber jar 以使用命令启动节点:java -jar。

  • 使用以下命令启动节点:

java -jar custom_node-server.jar node \ --node-implementation org.seleniumhq.samples.DecoratedLoggingNode

Explore our latest online courses and learn new skills at your own pace. Enroll and become a certified expert to boost your career.

使用普通 Jar 进行节点自定义

使用普通 jar 实现节点自定义的步骤如下所列:

  • 在系统中安装 Java(版本高于 8),并使用命令检查它是否存在:java -version。如果安装已成功完成,则将显示已安装的 Java 版本。

  • 在系统中安装 Maven,并使用命令检查它是否存在:mvn -version。如果安装已成功完成,则将显示已安装的 Maven 版本。

  • 安装任何 IDE,如 Eclipse、IntelliJ 等。

  • 从链接将 Selenium Grid 依赖项添加到 pom.xml 中:https://mvnrepository.com/artifact/

  • 从链接将 Apache Maven Shade Plugin 添加到 pom.xml 中:https://maven.apache.org/plugins/

  • 将自定义节点附加到当前项目。

  • 构建 uber jar 以使用命令启动节点:java -jar。

  • 使用以下命令启动节点:

java -jar selenium-server-4.6.0.jar \ --ext custom_node-1.0-SNAPSHOT.jar node \ --node-implementation org.seleniumhq.samples.DecoratedLoggingNode

DecoratedLoggingNode.java 中的代码实现

package org.seleniumhq.samples; import java.io.IOException; import java.net.URI; import java.util.UUID; import java.util.function.Supplier; import org.openqa.selenium.Capabilities; import org.openqa.selenium.NoSuchSessionException; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.grid.config.Config; import org.openqa.selenium.grid.data.CreateSessionRequest; import org.openqa.selenium.grid.data.CreateSessionResponse; import org.openqa.selenium.grid.data.NodeId; import org.openqa.selenium.grid.data.NodeStatus; import org.openqa.selenium.grid.data.Session; import org.openqa.selenium.grid.log.LoggingOptions; import org.openqa.selenium.grid.node.HealthCheck; import org.openqa.selenium.grid.node.Node; import org.openqa.selenium.grid.node.local.LocalNodeFactory; import org.openqa.selenium.grid.security.Secret; import org.openqa.selenium.grid.security.SecretOptions; import org.openqa.selenium.grid.server.BaseServerOptions; import org.openqa.selenium.internal.Either; import org.openqa.selenium.io.TemporaryFilesystem; import org.openqa.selenium.remote.SessionId; import org.openqa.selenium.remote.http.HttpRequest; import org.openqa.selenium.remote.http.HttpResponse; import org.openqa.selenium.remote.tracing.Tracer; public class DecoratedLoggingNode extends Node { private Node node; protected DecoratedLoggingNode(Tracer tracer, NodeId nodeId, URI uri, Secret registrationSecret) { super(tracer, nodeId, uri, registrationSecret); } public static Node create(Config config) { LoggingOptions loggingOptions = new LoggingOptions(config); BaseServerOptions serverOptions = new BaseServerOptions(config); URI uri = serverOptions.getExternalUri(); SecretOptions secretOptions = new SecretOptions(config); // Refer to the foot notes for additional context on this line. Node node = LocalNodeFactory.create(config); DecoratedLoggingNode wrapper = new DecoratedLoggingNode(loggingOptions.getTracer(), node.getId(), uri, secretOptions.getRegistrationSecret()); wrapper.node = node; return wrapper; } @Override public Either<WebDriverException, CreateSessionResponse> newSession( CreateSessionRequest sessionRequest) { return perform(() -> node.newSession(sessionRequest), "newSession"); } @Override public HttpResponse executeWebDriverCommand(HttpRequest req) { return perform(() -> node.executeWebDriverCommand(req), "executeWebDriverCommand"); } @Override public Session getSession(SessionId id) throws NoSuchSessionException { return perform(() -> node.getSession(id), "getSession"); } @Override public HttpResponse uploadFile(HttpRequest req, SessionId id) { return perform(() -> node.uploadFile(req, id), "uploadFile"); } @Override public HttpResponse downloadFile(HttpRequest req, SessionId id) { return perform(() -> node.downloadFile(req, id), "downloadFile"); } @Override public TemporaryFilesystem getDownloadsFilesystem(UUID uuid) { return perform(() -> { try { return node.getDownloadsFilesystem(uuid); } catch (IOException e) { throw new RuntimeException(e); } }, "downloadsFilesystem"); } @Override public TemporaryFilesystem getUploadsFilesystem(SessionId id) throws IOException { return perform(() -> { try { return node.getUploadsFilesystem(id); } catch (IOException e) { throw new RuntimeException(e); } }, "uploadsFilesystem"); } @Override public void stop(SessionId id) throws NoSuchSessionException { perform(() -> node.stop(id), "stop"); } @Override public boolean isSessionOwner(SessionId id) { return perform(() -> node.isSessionOwner(id), "isSessionOwner"); } @Override public boolean isSupporting(Capabilities capabilities) { return perform(() -> node.isSupporting(capabilities), "isSupporting"); } @Override public NodeStatus getStatus() { return perform(() -> node.getStatus(), "getStatus"); } @Override public HealthCheck getHealthCheck() { return perform(() -> node.getHealthCheck(), "getHealthCheck"); } @Override public void drain() { perform(() -> node.drain(), "drain"); } @Override public boolean isReady() { return perform(() -> node.isReady(), "isReady"); } private void perform(Runnable function, String operation) { try { System.err.printf("[COMMENTATOR] Before %s()%n", operation); function.run(); } finally { System.err.printf("[COMMENTATOR] After %s()%n", operation); } } private <T> T perform(Supplier<T> function, String operation) { try { System.err.printf("[COMMENTATOR] Before %s()%n", operation); return function.get(); } finally { System.err.printf("[COMMENTATOR] After %s()%n", operation); } } }

DecoratedLoggingNode.java 的源代码:https://selenium.net.cn/documentation/

在上述实现中,以下代码:

Node node = LocalNodeFactory.create(config) 用于专门生成 LocalNode。org.openqa.selenium.grid.node.Node 有两种面向用户的实现。这些是创建自定义节点和收集有关节点信息的绝佳起点。

  • org.openqa.selenium.grid.node.local.LocalNode - 用于指向长时间运行的节点,并且是启动节点时获取的默认逻辑。可以通过调用 LocalNodeFactory.create(config) 生成它。此处,LocalNodeFactory 是 org.openqa.selenium.grid.node.local 的一部分,Config 是 org.openqa.selenium.grid.config 的一部分。

  • org.openqa.selenium.grid.node.k8s.OneShotNode - 这是一个重要的参考逻辑,其中节点在一次测试会话后正确关闭自身。此类对任何预先存在的 Maven 工件不可用。可以通过调用 OneShotNode.create(config) 生成它。此处,OneShotNode 是 org.openqa.selenium.grid.node.k8s 的一部分,Config 是 org.openqa.selenium.grid.config 的一部分。

这结束了我们关于 Selenium Grid - 自定义节点教程的全面介绍。我们从描述如何在 Selenium Grid 中执行节点自定义、使用 uber jar 进行节点自定义以及在 Selenium Grid 中使用普通 jar 进行节点自定义开始。

这使您深入了解了 Selenium Grid 自定义节点。明智的做法是不断练习您学到的知识并探索与 Selenium 相关的其他知识,以加深您的理解并拓宽您的视野。

广告