1、
2、代码结构
3、代码
1)BasePage01类,用于存放公共方法
package com.po01;
import io.qameta.allure.Allure;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.io.FileUtils;
import javax.swing.text.Element;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDate;
import java.util.List;
public class BasePage01 {
public WebDriver driver;
public Logger logger = LoggerFactory.getLogger(“BasePage01.class”);
public BasePage01(String baseUrl) {
//当传入String类型的url,我们认为是用例的开始也就是一个初始页面,
driver = new ChromeDriver();
logger = LoggerFactory.getLogger(LoginPage01.class);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
logger.debug("开始自动化测试");
driver.get(baseUrl);
driver.manage().window().maximize();
}
public BasePage01(WebDriver baseDriver) {
driver = baseDriver;
}
//大量的driver find:
//1、每次查找元素添加日志--解决方法:不对外暴露driver,直接封装basepage
public WebElement find(By by){
System.out.println("sout查找元素为 =>"+by);
logger.debug("查找元素为 =>"+by);
return driver.findElement(by);
}
public List<WebElement> finds(By by){
logger.debug("查找元素为 =>"+by);
return driver.findElements(by);
}
public FluentWait<WebDriver> getFluentWait(){
FluentWait<WebDriver> fluentWait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(500))
.ignoring(ElementClickInterceptedException.class);
return fluentWait;
}
public void getUrl(String url){
logger.debug("跳转页面到 =>" + url);
driver.get(url);
}
public void quitDriver(){
driver.quit();
}
//页面截图
public void saveScreenShot() throws IOException {
LocalDate time = LocalDate.now();
File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(screenshot,new File("src/test/resources/imgs/"+time+".png"));
Allure.addAttachment("页面截图","image/png",new FileInputStream("src/test/resources/imgs/"+time+".png"),".png");
}
//错误信息
public void saveErrorInfo(String error){
Allure.addAttachment("报错信息",error);
}
}
2)登录页面LoginPage01
package com.po01;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class LoginPage01 extends BasePage01{
//问题:driver 初始化和具体的业务操作结合了,比如测试用例一量没有登录步骤,那么就无法进行打开浏览器以及页面等待操作
//解决方法:将 driver 初始化,在一开始就完成,也就是构造函数
//所有初始页面都需要添加这个方法
//问题:元素定位没有统一维护,一但页面发生变化,那么相关的位置都要改
private final By usernameInputBy = By.name("username");
private final By passwordInputBy = By.name("password");
private final By loginButtonBy = By.cssSelector("button");
public LoginPage01(String baseUrl){
super(baseUrl);
}
public LoginPage01(WebDriver baseDriver) {
super(baseDriver);
}
public MainPage01 login(String username,String password){
find(usernameInputBy).clear();
find(usernameInputBy).sendKeys(username);
find(passwordInputBy).clear();
find(passwordInputBy).sendKeys(password);
find(loginButtonBy).click();
return new MainPage01(driver);
}
}
3)主页面MainPage01
package com.po01;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
public class MainPage01 extends BasePage01{
//问题:虽然继承了,但是依然一直重复的打开浏览器,每次new一个新的page,只要继承了base page 就会不这的重复打开浏览器
//解决方法:添加带参的BasePage构造函数
private final By manageMarketButton = By.xpath("//*[text()='商场管理']");
private final By produceCategoryButton = By.xpath("//ul//*[text()='商品类目']");
public MainPage01(WebDriver baseDriver) {
super(baseDriver);
}
public CategoryPage01 gotoCategoryPage() {
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
getFluentWait().until(ExpectedConditions.elementToBeClickable(manageMarketButton)).click();
find(produceCategoryButton).click();
return new CategoryPage01(driver);
}
}
4)CategoryPage01 商品类目页面
package com.po01;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import java.util.List;
public class CategoryPage01 extends BasePage01{
//添加按钮
private final By categoryButton = By.cssSelector(“.el-icon-edit”);
//删除按钮
// private final By deleteButton = By.xpath(“//[text()=‘123’]/…/…//[text()=‘删除’]”);
public CategoryPage01(WebDriver baseDriver) {
super(baseDriver);
}
//进入添加页面
public CreatCategoryPage01 gotoCreateCategoryPage(){
find(categoryButton).click();
return new CreatCategoryPage01(driver);
}
//获取结果列表
public List<WebElement> getResult(String categoryName){
List<WebElement> eles = finds(By.xpath("//*[text()='"+categoryName+"']"));
return eles;
}
public void deleteCategory(String categoryName){
find(By.xpath("//*[text()='"+categoryName+"']/../..//*[text()='删除']")).click();
}
}
5)CreatCategoryPage01创建商品类目页
package com.po01;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
public class CreatCategoryPage01 extends BasePage01{
private final By produceNameInput = By.cssSelector(".el-form-item:nth-child(1) input");
private final By prodeceSubmitButton = By.cssSelector(".el-dialog__footer .el-button--primary");
private final By popInfo = By.cssSelector(".el-notification__title");
// private final By producesList = By.xpath(“//*[text()=‘测试添加商品’]”);
private final By errorMessage = By.cssSelector(“.el-form-item__error”);
public CreatCategoryPage01(WebDriver baseDriver) {
super(baseDriver);
}
public CategoryPage01 createCategory(String categoryName){
find(produceNameInput).sendKeys(categoryName);
getFluentWait().until(driver1 -> {
driver1.findElement(prodeceSubmitButton).click();
return find(popInfo);
});
return new CategoryPage01(driver);
}
public String createCategoryfail(){
find(produceNameInput).sendKeys("");
getFluentWait().until(ExpectedConditions.elementToBeClickable(prodeceSubmitButton)).click();
return find(errorMessage).getText();
}
}
6)测试方法
package com.po01;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.openqa.selenium.WebElement;
import java.io.IOException;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class CreatCategoryPage01Test {
public static LoginPage01 loginPage01;
public static CategoryPage01 categoryPage01;
@BeforeAll
public static void setUp(){
loginPage01 = new LoginPage01("http://litemall.hogwarts.ceshiren.com/#/login");
categoryPage01 = loginPage01.login("manage","manage123").gotoCategoryPage();
}
//问题:上一个用例的结束会影响下一个用例
//解决方法:使用url跳转的方式,回退到用例执行之前的初始状态,保证下一个用例仍然能够正常执行
@AfterEach
void tearDowns(){
categoryPage01.getUrl("http://litemall.hogwarts.ceshiren.com/#/mall/category");
}
@ParameterizedTest(name = "商品类目参数化" )
@ValueSource(strings = {"测试商品hogwarts01", "测试商品hogwarts02"})
void createCategory(String categoryName) {
try {
categoryPage01
.gotoCreateCategoryPage()
.createCategory(categoryName);
//1、在商品列表页获取结果信息
List<WebElement> lists = categoryPage01.getResult(categoryName);
assertEquals(1,lists.size());
categoryPage01.saveScreenShot();
//2、在商品列表页删除操作
categoryPage01.deleteCategory(categoryName);
categoryPage01.saveScreenShot();
} catch (IOException e) {
categoryPage01.saveErrorInfo(e.toString());
}
}
//异常的场景
@Test
void createCategoryFail() {
String errorInfo = categoryPage01
.gotoCreateCategoryPage()
.createCategoryfail();
assertEquals("类目名不能为空",errorInfo);
try {
categoryPage01.saveScreenShot();
} catch (IOException e) {
categoryPage01.saveErrorInfo(e.toString());
}
}
@AfterAll
public static void tearDown(){
loginPage01.quitDriver();
}
}
4、pom信息
<?xml version="1.0" encoding="UTF-8"?> xmlns=“http://maven.apache.org/POM/4.0.0”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>
4.0.0
<groupId>org.example</groupId>
<artifactId>hogwarts24advence</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version>
<!-- 使用 Java 11 语言特性 ( -source 11 ) 并且还希望编译后的类与 JVM 11 ( -target 11 )兼容,您可以添加以下两个属性,它们是默认属性插件参数的名称-->
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<!-- 对应junit Jupiter的版本号;放在这里就不需要在每个依赖里面写版本号,导致对应版本号会冲突-->
<junit.jupiter.version>5.8.2</junit.jupiter.version>
<maven.compiler.version>3.8.1</maven.compiler.version>
<maven.surefire.version>3.0.0-M5</maven.surefire.version>
<!-- plugins -->
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<poi.version>5.2.2</poi.version>
</properties>
<!-- 物料清单 (BOM)-->
<dependencyManagement>
<dependencies>
<!--当使用 Gradle 或 Maven 引用多个 JUnit 工件时,此物料清单 POM 可用于简化依赖项管理。不再需要在添加依赖时设置版本-->
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit.jupiter.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<!-- 对应添加的依赖的作用范围-->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<!-- <version>${junit.jupiter.version}</version>-->
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-api</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>2.13.6</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-support</artifactId>
<version>4.2.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<!-- <includes>-->
<!-- <include>top/testeru/group/*_Test.class</include>-->
<!-- </includes>-->
</configuration>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
</plugin>
</plugins>
</build>
5、logback.xml配置信息
<?xml version="1.0" encoding="UTF-8" ?> %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36}.%M\(%line\) -- %msg%n<logger name="po01" level="DEBUG" />
<logger name="litemall" level="DEBUG" />
<logger name="com.ceshiren" level="DEBUG" />
<logger name="com" level="DEBUG" />
<logger name="ceshiren" level="DEBUG" />
<logger name="org" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>