内容
# Selenium Boot
**一款面向 Java 自动化测试的零模板、生产就绪框架**
[](https://central.sonatype.com/artifact/io.github.seleniumboot/selenium-boot)
[](LICENSE)
**[文档](https://seleniumboot.github.io/selenium-boot) · [示例项目](https://github.com/seleniumboot/selenium-boot-test) · [更新日志](#项目状态)**
---
> **Selenium Boot 用户的 AI 驱动测试编写**
> 使用 **seleniumboot-mcp** 让 Claude / GitHub Copilot 控制真实浏览器,记录您的会话,并生成可立即运行的 Selenium Boot 测试代码 — TestNG、JUnit 5、页面对象、Gherkin 或 C# NUnit。
> ```
> pip install seleniumboot-mcp
> ```
> [PyPI](https://pypi.org/project/seleniumboot-mcp/) · [GitHub](https://github.com/seleniumboot/selenium-mcp) · 84 种工具 · 自我修复定位符 · Java / Python / C# / Playwright 的代码生成
---
## 概述
Selenium Boot 是一个面向 Java Selenium 的零模板、生产就绪的自动化框架,其灵感来自 Spring Boot 的哲学思想。
它通过提供合理的默认值、标准化的项目结构和约定优于配置的方法来消除重复的模板,同时保持 Selenium 的完全可见性和可访问性。
---
## 开箱即用的功能
- 自动 WebDriver 生命周期管理(无需设置/拆卸模板)
- 基于 YAML 的配置,支持环境配置文件切换
- 并行执行,线程安全的驱动程序隔离
- 通过 `WaitEngine` 实现智能显式等待 - 不再需要 `Thread.sleep()`
- 通过 `@Retryable` 实现重试机制,适用于易失性测试
- 测试失败时捕获截图,嵌入报告中
- 高级 HTML 报告 - 通过率表、甜甜圈图、最慢测试、步骤时间线、暗黑模式
- `BasePage` - 等待支持的 `click`、`type`、`getText`、`isDisplayed`、`iFrame` 助手、文件上传
- `SmartLocator` - 尝试多种 `By` 策略,按顺序返回第一个可见元素
- **无障碍优先的定位符** - `getByRole`、`getByText`、`getByLabel`、`getByPlaceholder`、`getByTestId`、`getByAltText`、`getByTitle`;针对用户感知的无障碍树进行定位,以便测试在 CSS/DOM 重构后仍然有效(类似 Playwright,自动等待)
- `@PreCondition` - 会话感知的预条件,自动缓存 cookie + localStorage
- `ConsoleErrorCollector` - 捕获 JS 控制台错误(Chrome 通过日志,Firefox 通过 shim)
- `DownloadManager` - 轮询下载目录,处理部分文件
- `StepLogger` - 命名测试步骤,带有时间戳和每步截图
- **API 测试** - `BaseApiTest` 进行纯 API 测试;流畅的 `ApiClient`,支持身份验证、模式验证、JSONPath;同一套件中的混合 UI + API 测试
- **无障碍断言** - `accessibility().withTags("wcag2a","wcag21aa").withLevel(Impact.SERIOUS).run()` - axe-core 捆绑在 JAR 中,无需额外依赖;作用域扫描、排除选择器、流畅的 `Impact` 级别过滤器
- 插件系统 - 自定义浏览器提供程序、报告适配器、生命周期钩子,通过 Java SPI
- CI 就绪 - 自动检测 GitHub Actions、Jenkins、CircleCI;强制启用无头模式,发出 JUnit XML
---
## 快速入门
### 先决条件
- Java 17+
- Maven 3.8+
- 已安装 Chrome 或 Firefox
无需 WebDriver 二进制文件 - Selenium Manager 自动处理。
---
### 步骤 1:添加依赖项
在您的 `pom.xml` 中添加:
```xml
<dependency>
<groupId>io.github.seleniumboot</groupId>
<artifactId>selenium-boot</artifactId>
<version>3.1.1</version>
</dependency>
```
同时添加 Surefire 插件,以便 `mvn test` 发现 TestNG 测试:
```xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
</plugins>
</build>
```
---
### 步骤 2:创建配置文件
在您的**项目根目录**(与 `pom.xml` 相同级别)创建 `selenium-boot.yml`:
```yaml
execution:
mode: local # local | remote
baseUrl: https://example.com
parallel: methods # none | methods | classes
threadCount: 4
maxActiveSessions: 4
browser:
name: chrome # chrome | firefox
headless: false
lifecycle: per-test # per-test (default) | per-suite
captureConsoleErrors: true
arguments:
- --start-maximized
- --disable-notifications
retry:
enabled: true
maxAttempts: 2
timeouts:
explicit: 10 # seconds — used by WaitEngine
pageLoad: 30 # seconds
```
这是唯一需要的配置文件。所有字段都有默认值 - 从最小配置开始:
```yaml
execution:
mode: local
baseUrl: https://example.com
browser:
name: chrome
```
---
### 步骤 3:项目结构
```
your-project/
├── pom.xml
├── selenium-boot.yml
└── src/
└── test/
└── java/
└── com/yourcompany/
├── conditions/
│ └── AppConditions.java
├── pages/
│ └── LoginPage.java
└── tests/
└── LoginTest.java
```
---
### 步骤 4:创建页面对象
扩展框架内置的 `BasePage` - 它提供等待支持的交互助手:
```java
package com.yourcompany.pages;
import com.seleniumboot.test.BasePage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class LoginPage extends BasePage {
private final By usernameField = By.id("username");
private final By passwordField = By.id("password");
private final By loginButton = By.id("login-btn");
public LoginPage(WebDriver driver) {
super(driver);
}
public void login(String username, String password) {
type(usernameField, username);
type(passwordField, password);
click(loginButton);
}
}
```
`BasePage` 提供:`click`、`type`、`getText`、`getAttribute`、`isDisplayed`、`withinFrame`、`withinFrameIndex`、`upload`。所有操作都支持等待 - 无需手动等待。
---
### 步骤 5:编写测试
扩展 `BaseTest` - 这是所需的全部设置:
```java
package com.yourcompany.tests;
import com.seleniumboot.steps.StepLogger;
import com.seleniumboot.test.BaseTest;
import com.yourcompany.pages.LoginPage;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
public class LoginTest extends BaseTest {
@Test
public void loginWithValidCredentials() {
StepLogger.step("Open login page");
open();
StepLogger.step("Enter credentials and submit", true);
new LoginPage(getDriver()).login("admin", "password123");
assertTrue(getDriver().getCurrentUrl().contains("/dashboard"));
}
}
```
**规则:**
- 始终扩展 `BaseTest`
- 永远不要手动实例化或退出 `WebDriver` - 框架管理它
- 使用 `getDriver()` 访问当前线程的驱动程序实例
- 使用 `open()` 导航到 `baseUrl`,或使用 `open("/path")` 访问子路径
---
### 步骤 6:运行测试
```bash
mvn test
```
就这样。Selenium Boot 自动处理驱动程序创建、并行执行、重试、截图和报告生成。
---
### 步骤 7:查看报告
执行后,打开 HTML 报告:
```
target/selenium-boot-report.html
```
报告包括:
- 带有颜色编码的通过率表
- 甜甜圈图 - 通过/失败/跳过分布
- 每个测试的执行时间和重试徽章
- 每个测试的步骤时间线
- 失败截图(base64 嵌入,点击展开)
- 暗黑模式切换
---
## @PreCondition - 会话缓存
消除重复的登录模板。声明一次条件,缓存会话,在多个测试中重用:
```java
// 1. 定义条件
public class AppConditions extends BaseConditions {
@ConditionProvider("loginAsAdmin")
public void loginAsAdmin() {
open("/");
new LoginPage(getDriver()).login("admin", "secret");
}
}
```
```
// 2. 通过 SPI 注册
src/test/resources/META-INF/services/com.seleniumboot.precondition.BaseConditions
→ com.yourcompany.conditions.AppConditions
```
```java
// 3. 在测试中使用
@Test
@PreCondition("loginAsAdmin")
public void viewDashboard() {
open("/dashboard"); // 会话已建立 - 无需重新登录
}
@Test
@PreCondition("loginAsAdmin")
public void editProfile() {
open("/profile"); // 会话从缓存中恢复
}
```
缓存是每个线程的 - 对并行执行来说是安全的。在重试时,缓存将被失效,条件将重新运行。
---
## API 测试
Selenium Boot 支持**纯 API 测试**和**混合 UI + API 测试** - 相同的框架,相同的配置,相同的 HTML 报告。
### 纯 API 测试
扩展 `BaseApiTest` 而不是 `BaseTest`。不会启动浏览器。
```java
public class UserApiTest extends BaseApiTest {
@Test
public void getUserById() {
ApiClient.get("https://api.example.com/users/1")
.send()
.assertStatus(200)
.assertJson("$.name", "John Doe");
}
}
```
### `ApiClient` - 流畅的 HTTP 客户端
```java
// GET
ApiClient.get("/api/users").send();
// POST with body
ApiClient.post("/api/users")
.body(Map.of("name", "Alice", "email", "alice@example.com"))
.send()
.assertStatus(201);
// Custom header
ApiClient.get("/api/orders")
.header("X-Request-ID", "abc123")
.send();
// Different base URL for one request
ApiClient.to("https://other-service.com").get("/health").send();
```
在 `selenium-boot.yml` 中配置默认基准 URL:
```yaml
api:
baseUrl: https://api.example.com
timeoutSeconds: 30
logBody: false # set true to include body in step timeline
```
### `ApiResponse` - 断言和提取
```java
ApiResponse res = ApiClient.get("/api/users/1").send();
res.assertStatus(200);
res.assertBodyContains("Alice");
res.assertJson("$.name", "Alice");
// Extract values
String name = res.json("$.name");
int id = res.json("$.id", Integer.class);
User user = res.asObject(User.class);
// Fluent chaining
res.assertStatus(200)
.assertJson("$.name", "Alice")
.assertSchema("schemas/user.json");
```
### 身份验证
**Bearer token:**
```java
ApiClient.get("/api/me")
.auth(ApiAuth.bearerToken("my-token"))
.send();
```
**Basic auth:**
```java
ApiClient.get("/api/admin")
.auth(ApiAuth.basicAuth("user", "pass"))
.send();
```
**一次性为整个套件设置身份验证** - 所有请求自动使用它:
```java
@BeforeSuite
public void authenticate() {
ApiResponse login = ApiClient.post("/api/auth/login")
.body(Map.of("username", "admin", "password", "pass"))
.send();
ApiClient.setGlobalAuth(ApiAuth.bearerToken(login.json("$.token")));
}
```
**OAuth2 客户端凭证** - 自动获取和缓存令牌:
```java
ApiClient.setGlobalAuth(ApiAuth.oauth2(
"https://auth.example.com/token",
System.getenv("CLIENT_ID"),
System.getenv("CLIENT_SECRET")
));
```
**基于配置的身份验证与`@UseAuth`** - 在 YAML 中定义策略,按测试应用:
```yaml
api:
auth:
adminToken:
type: bearer
token: ${ADMIN_TOKEN} # resolved from env var
serviceAccount:
type: oauth2
tokenUrl: https://auth.example.com/token
clientId: ${CLIENT_ID}
clientSecret: ${CLIENT_SECRET}
```
```java
@Test
@UseAuth("adminToken")
public void createUser() {
ApiClient.post("/api/users").body(...).send().assertStatus(201);
}
```
### 模式验证
使用 JSON 模式文件验证响应结构:
```java
ApiClient.get("/api/users/1")
.send()
.assertStatus(200)
.assertSchema("schemas/user.json");
```
将模式文件放在 `src/test/resources/schemas/` 下。需要一个额外的依赖项:
```xml
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.4.3</version>
</dependency>
```
### 混合 UI + API 测试
在同一个测试中使用 `apiClient()` 在 `BaseTest` 中混合 API 调用和浏览器交互:
```java
public class CheckoutTest extends BaseTest {
@Test
public void placeOrder() {
// Set up via API (fast, no UI navigation)
String orderId = apiClient().post("/api/orders")
.body(Map.of("productId", 42, "qty", 1))
.send()
.assertStatus(201)
.json("$.orderId");
// Verify in the UI
open("/orders/" + orderId);
Assert.assertEquals(getText(By.id("status")), "Pending");
}
}
```
### 场景和套件上下文
在测试内或跨测试共享状态而无需静态字段:
```java
// ScenarioContext - 仅限一个测试,自动清除后
ctx().set("token", loginRes.json("$.token"));
String token = ctx().get("token");
// SuiteContext - 在测试之间存活,线程安全
suiteCtx().set("createdUserId", res.json("$.id")); // in test 1
String userId = suiteCtx().get("createdUserId"); // in test 2
```
---
## WaitEngine 参考
`WaitEngine` 使用您的配置中的 `timeouts.explicit` 值。永远不要使用 `Thread.sleep()`。
```java
import com.seleniumboot.wait.WaitEngine;
import org.openqa.selenium.By;
WebElement el = WaitEngine.waitForVisible(By.id("submit-btn"));
WebElement btn = WaitEngine.waitForClickable(By.cssSelector(".next-btn"));
WaitEngine.waitForTitle("Dashboard");
WaitEngine.waitForUrlContains("/dashboard");
WaitEngine.waitForText(By.id("status"), "Complete");
WaitEngine.waitForPageLoad();
```
---
## 重试参考
添加 `@Retryable` 到任何 `@Test` 方法以启用失败时重试。重试次数由您的配置中的 `retry.maxAttempts` 控制。重试可以全局禁用 `retry.enabled: false`。
```java
@Retryable
@Test
public void flakyTest() {
// 如果失败,最多重试 maxAttempts 次
}
```
---
## 远程执行(Selenium Grid)
更新 `selenium-boot.yml`:
```yaml
execution:
mode: remote
baseUrl: https://example.com
gridUrl: http://localhost:4444/wd/hub
parallel: methods
threadCount: 4
browser:
name: chrome
headless: true
```
无需代码更改 - 仅需配置。
---
## 环境配置文件
按环境命名您的配置文件并使用系统属性激活:```
selenium-boot.yml # default
selenium-boot-staging.yml # staging profile
selenium-boot-prod.yml # prod profile
```
```bash
mvn test -Denv=staging
```
---
## 扩展框架
Selenium Boot 提供了四个扩展点。所有支持 **Java SPI**(自动发现)和**编程注册**。
### 自定义驱动程序提供程序
```java
public class EdgeDriverProvider implements NamedDriverProvider {
@Override public String browserName() { return "edge"; }
@Override public WebDriver createDriver() { return new EdgeDriver(); }
```
通过 SPI 注册 (`META-INF/services/com.seleniumboot.driver.NamedDriverProvider`) 或:
```java
DriverProviderRegistry.register(new EdgeDriverProvider());
```
### 自定义报告适配器
```java
public class SlackReportAdapter implements ReportAdapter {
@Override public String getName() { return "slack"; }
@Override public void generate(File metricsJson) { /* post to Slack */ }
```
通过 SPI 注册 (`META-INF/services/com.seleniumboot.reporting.ReportAdapter`) 或:
```java
ReportAdapterRegistry.register(new SlackReportAdapter());
```
### 生命周期钩子
```java
public class TimingHook implements ExecutionHook {
@Override
public void onTestFailure(String testId, Throwable cause) {
alerting.notify(testId, cause.getMessage());
}
```
可用事件:`onSuiteStart`, `onSuiteEnd`, `onTestStart`, `onTestEnd`, `onTestFailure`.
### 插件系统
将驱动程序组合多个驱动程序提供程序、报告适配器和钩子到一个可部署的单元中:
```java
public class MyPlugin implements SeleniumBootPlugin {
@Override public String getName() { return "my-plugin"; }
@Override public void onLoad(SeleniumBootConfig config) {
ReportAdapterRegistry.register(new SlackReportAdapter());
}
}
```
声明框架版本最低要求以防止不兼容:
```java
@Override public String minFrameworkVersion() { return "0.8.0"; }
```
---
## CI/CD 集成
Selenium Boot 自动检测 CI 环境并应用合理的默认值 - 无需更改 YAML。
- `browser.headless` 强制为 `true`
- `threadCount` 自动根据可用 CPU 核心数导出
- Chrome 自动应用 Docker/容器标志 (`--no-sandbox`, `--disable-dev-shm-usage`)
- 每运行一次测试,都会将 JUnit XML 写入 `target/surefire-reports/TEST-SeleniumBoot.xml`
### 构建质量门
```yaml
ci:
failOnPassRateBelow: 80 # 如果通过率低于 80%,则构建失败
maxFlakyTests: 3 # 如果超过 3 个测试重试,则构建失败
```
---
## 项目状态
**当前版本:v3.1.1** - 每个引擎的报告输出目录(`seleniumboot.reports.dir`),修复报告覆盖问题,当 TestNG + JUnit 5 在一个构建中运行时。
在 **[CHANGELOG.md](CHANGELOG.md)** 中查看完整的版本历史。
---
## 示例项目
一个涵盖所有框架功能的示例项目可在以下位置找到:
**[github.com/seleniumboot/selenium-boot-test](https://github.com/seleniumboot/selenium-boot-test)**
---
## 文档
**[seleniumboot.github.io/selenium-boot](https://seleniumboot.github.io/selenium-boot)**
---
## 许可
根据 [Apache License, Version 2.0](LICENSE) 授权。
---
## 贡献
参见 [CONTRIBUTING.md](CONTRIBUTING.md)。
---
## 免责声明
Selenium Boot 是一个独立的开源项目,与 Selenium 或 Spring Framework 无关。
连接信息
猜你喜欢
暂无推荐服务器