01 使用JUnit5执行测试脚本
Playwright
测试可以通过多种方式进行。我们建议将它连接到你最喜欢的测试运行器,例如JUnit
,JUint
能够并行运行测试、运行单个测试等。
你可以运行单个测试、一组测试或所有测试。测试可以在一个浏览器或多个浏览器上运行。默认情况下,测试以无头方式运行,这意味着在运行测试时不会打开浏览器窗口,并且会在终端中看到结果。如果你愿意,可以使用launch(new BrowserType.LaunchOptions().setHeadless(false))
选项以引导模式运行测试。
Playwright
和 Browser
实例可以在测试之间重复使用以获得更好的性能。建议在新的 BrowserContext
中运行每个测试用例,这样浏览器状态将在测试之间隔离。
在JUnit
中,你可以在@BeforeAll
方法中初始化Playwright
和Browser
并在@AfterAll
中销毁它们。在下面的示例中,所有三种测试方法都使用相同的Browser
。每个测试都使用自己的BrowserContext
和Page
。
import com.microsoft.playwright.*;
import org.junit.jupiter.api.*;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author 作者:测试工程师成长之路
* @version 创建时间:2023/5/10
* 类说明:使用JUnit运行测试用例
*/
public class JUnitTest {
// 该类所有测试之间共享
static Playwright playwright;
static Browser browser;
// 为每个测试方法建立新的实例。
BrowserContext context;
Page page;
@BeforeAll
static void launchBrowser() {
System.out.println("初始化浏览器,打开chrome");
playwright = Playwright.create();
browser = playwright.chromium().launch(new BrowserType.LaunchOptions()
.setChannel("chrome")
.setHeadless(false));
}
@AfterAll
static void closeBrowser() {
System.out.println("关闭浏览器");
playwright.close();
}
@BeforeEach
void createContextAndPage() {
System.out.println("创建context和page");
context = browser.newContext(new Browser.NewContextOptions().setViewportSize(1440,1880));
page = context.newPage();
}
@AfterEach
void closeContext() {
System.out.println("关闭context");
context.close();
}
@Test
void shouldClickButton() throws InterruptedException {
System.out.println("执行测试用例:shouldClickButton");
page.navigate("data:text/html,<script>var result;</script><button onclick='result=\"Clicked\"'>Go</button>");
page.locator("button").click();
assertEquals("Clicked", page.evaluate("result"));
Thread.sleep(3000);
}
@Test
void shouldCheckTheBox() throws InterruptedException {
System.out.println("执行测试用例:shouldCheckTheBox");
page.setContent("<input id='checkbox' type='checkbox'></input>");
page.locator("input").check();
assertTrue((Boolean) page.evaluate("() => window['checkbox'].checked"));
Thread.sleep(3000);
}
@Test
void shouldSearchWiki() throws InterruptedException {
System.out.println("执行测试用例:shouldSearchWiki");
page.navigate("https://www.wikipedia.org/");
page.locator("input[name=\"search\"]").click();
page.locator("input[name=\"search\"]").fill("playwright");
page.locator("input[name=\"search\"]").press("Enter");
assertEquals("https://en.wikipedia.org/wiki/Playwright", page.url());
Thread.sleep(3000);
}
}
02 并发执行测试脚本
默认情况下,JUnit
将在单个线程上按顺序运行所有测试。从 JUnit 5.3
开始,你可以更改此行为以并行运行测试以加快执行速度。由于在没有额外同步的情况下从多个线程使用相同的 Playwright
对象是不安全的,我们建议你为每个线程创建 Playwright
实例并在该线程上独占使用它。这是一个如何并行运行多个测试类的示例。使用
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
注释使 JUnit
为该类中的所有测试方法创建一个类的实例(默认情况下,每个 JUnit
将为每个测试方法创建一个新的类实例)。在实例字段中存储Playwright
和Browser
对象。它们将在测试之间共享。该类的每个实例都将使用它自己的 Playwright
副本。
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author 作者:测试工程师成长之路
* @version 创建时间:2023/5/10
* 类说明:并行运行测试用例1
*/
public class JUnitThreadTest1 extends JUnitTest{
@Test
void shouldClickButton() throws InterruptedException {
System.out.println(this.getClass() + "-shouldClickButton-" + Thread.currentThread().getName());
page.navigate("data:text/html,<script>var result;</script><button onclick='result=\"Clicked\"'>Go</button>");
page.locator("button").click();
assertEquals("Clicked", page.evaluate("result"));
Thread.sleep(3000);
}
@Test
void shouldCheckTheBox() throws InterruptedException {
System.out.println(this.getClass() + "-shouldCheckTheBox-" + Thread.currentThread().getName());
page.setContent("<input id='checkbox' type='checkbox'></input>");
page.locator("input").check();
assertTrue((Boolean) page.evaluate("() => window['checkbox'].checked"));
Thread.sleep(3000);
}
@Test
void shouldSearchWiki() throws InterruptedException {
System.out.println(this.getClass() + "-shouldSearchWiki-" + Thread.currentThread().getName());
page.navigate("https://www.wikipedia.org/");
page.locator("input[name=\"search\"]").click();
page.locator("input[name=\"search\"]").fill("playwright");
page.locator("input[name=\"search\"]").press("Enter");
assertEquals("https://en.wikipedia.org/wiki/Playwright", page.url());
Thread.sleep(3000);
}
}
import com.microsoft.playwright.Page;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author 作者:测试工程师成长之路
* @version 创建时间:2023/5/10
* 类说明:并行运行测试用例2
*/
public class JUnitThreadTest2 extends JUnitThread {
@Test
void shouldReturnInnerHTML() throws InterruptedException {
System.out.println(this.getClass() + "-shouldReturnInnerHTML-" + Thread.currentThread().getName());
page.setContent("<div>hello</div>");
assertEquals("hello", page.innerHTML("css=div"));
Thread.sleep(3000);
}
@Test
void shouldClickButton() throws InterruptedException {
System.out.println(this.getClass() + "-shouldClickButton-" + Thread.currentThread().getName());
Page popup = page.waitForPopup(() -> {
page.evaluate("window.open('about:blank');");
});
assertEquals("about:blank", popup.url());
Thread.sleep(3000);
}
}
import org.junit.platform.runner.JUnitPlatform;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.runner.RunWith;
/**
* @author 作者:jinzy
* @version 创建时间:2023/5/10
* 类说明:并行运行测试用例
*/
@RunWith(JUnitPlatform.class)
@SelectClasses( {JUnitThreadTest1.class,JUnitThreadTest2.class})
public class JUnitThreadRunner {
}
配置 JUnit
以在每个类中按顺序运行测试并在并行线程上运行多个类(最大线程数等于 CPU
内核数的 1/2
),在src/main/resources
下创建junit-platform.properties
文件,文件内容如下
# 是否允许并行执行true/false
junit.jupiter.execution.parallel.enabled = true
# 是否支持方法级别多线程same_thread/concurrent
junit.jupiter.execution.parallel.mode.default = same_thread
# 是否支持类级别多线程same_thread/concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.config.dynamic.factor=0.5
03 自动生成测试脚本
Playwright
具有开箱即用的生成测试脚本的功能,是快速开始编写测试脚本的最佳方法。它将打开两个窗口,一个是浏览器窗口,可以在其中与要测试的网站进行交互,另一个是 Playwright Inspector
窗口,可以在其中记录测试、复制测试、清除测试以及更改测试语言。
1.运行测试生成器
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="codegen demo.playwright.dev/todomvc"
2.代码录制
codegen
在浏览器中运行和执行操作。Playwright
将为用户交互生成代码。Codegen
将查看呈现的页面并找出推荐的定位器、优先级角色、文本和测试 id
定位器。如果生成器识别出与定位器匹配的多个元素,它将改进定位器,使其具唯一标识目标元素,从而消除和减少由于定位器导致的测试失败。
按下Record
按钮停止录制,Pick Locator
按钮将出现。单击该Pick Locator
按钮,然后将鼠标悬停在浏览器窗口中的元素上,以查看每个元素下方突出显示的定位器。要选择一个定位器,请单击要定位的元素,该定位器的代码将出现在“选择定位器”按钮旁边的字段中。然后,可以在此字段中编辑定位器以对其进行微调,或使用复制按钮将其复制并粘贴到代码中。
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.AriaRole;
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.*;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import java.util.*;
/**
* @author 作者:测试工程师成长之路
* @version 创建时间:2023/5/10
* 类说明: 自动生成测试脚本
* 打开终端或idea终端,执行:mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="codegen demo.playwright.dev/todomvc"
*/
public class CodegenRecordTest {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions()
.setHeadless(false));
BrowserContext context = browser.newContext();
Page page = context.newPage();
page.navigate("https://demo.playwright.dev/todomvc/");
page.navigate("https://demo.playwright.dev/todomvc/#/");
page.getByPlaceholder("What needs to be done?").click();
page.getByPlaceholder("What needs to be done?").fill("playwright");
page.getByPlaceholder("What needs to be done?").press("Enter");
page.getByRole(AriaRole.CHECKBOX, new Page.GetByRoleOptions().setName("Toggle Todo")).check();
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Active")).click();
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Completed")).click();
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Clear completed")).click();
}
}
}