针对前面的博客系统项目进行自动化实战 - 项目链接 : 博客系统SSM
1. 创建一个 Maven 项目
2. 在 test 包下的 java 下建包管理自己后续要写的代码. 例如 : com.blogWebAutoTest, 再在 blogWebAutoTest 包下建两个包 common, Tests.
3. 导入自动化测试需要的相关依赖.
org.seleniumhq.selenium
selenium-java
4.0.0
commons-io
commons-io
2.6
org.junit.jupiter
junit-jupiter
5.8.2
test
org.junit.platform
junit-platform-suite
1.8.2
test
在 common 包下创建 AutoTestUtils 类, 该类主要提供的功能有 :
public class AutoTestUtils {
public static EdgeDriver driver;
// 创建驱动对象
public static EdgeDriver getDriver() {
if(driver == null) {
driver = new EdgeDriver();
}
// 创建隐式等待,作用于driver的整个生命周期 (10秒)
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
return driver;
}
// 屏幕截图, 保存文件的格式
public List getTime() {
// 文件夹按照天数的维度进行保存
// 文件格式 2023-4-3 20:07
SimpleDateFormat sim1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
SimpleDateFormat sim2 = new SimpleDateFormat("yyyy-MM-dd");
String filename = sim1.format(System.currentTimeMillis());
String dirname = sim2.format(System.currentTimeMillis());
List list = new ArrayList<>();
list.add(dirname);
list.add(filename);
return list;
}
// 屏幕截图的方法
public void getScreenShotAs(String str) throws IOException {
List list = getTime();
String filePath = "./src/test/java/com/blogWebAutoTest/"+list.get(0)+"/"+str+"_"+list.get(1)+".png";
File srcFile = driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File(filePath));
}
}
在 Tests 包下创建 DriverQuitTest 类, 该类主要是用来释放驱动的. (放在测试套件的最后一个)
public class DriverQuitTest extends AutoTestUtils {
public static EdgeDriver driver;
@Test
void driverQuit() {
driver = getDriver();
driver.quit();
}
}
创建 BlogRegTest 类, 该类的测试用例主要有 4 个:
其他的用户名为空, 密码为空, 确认密码为空, 就不测了, 下面的登录有类似的.
相关代码 :
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogRegTest extends AutoTestUtils {
public static EdgeDriver driver;
@BeforeAll
static void baseController() {
driver = getDriver();
driver.get("http://43.139.1.94:8080/reg.html");
}
/**
* 检查注册页面是否能够正常打开
* 检查登录页的导航栏的登录按钮,以及确认密码是否出现
*/
@Test
@Order(1)
void loginPageLoadRight() throws IOException {
driver.findElement(By.cssSelector("#password2"));
driver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
getScreenShotAs(getClass().getName());
}
/**
* 检查正常注册的情况
* 两次弹窗
*/
@ParameterizedTest
@CsvSource({"李白,123,123"})
@Order(2)
void loginSuccess(String username,String password,String password2) throws IOException, InterruptedException {
// 注册之前先清空用户名,密码和确认密码
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#password2")).clear();
// 注册步骤
driver.findElement(By.cssSelector("#username")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#password2")).sendKeys(password2);
driver.findElement(By.cssSelector("#submit")).click();
// 检测注册结果 , 第一个弹窗显示注册成功, 第二个弹窗显示是否要去登录页面
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
// 警告弹窗
alert.accept();
// 确认弹窗
Thread.sleep(100);
alert.dismiss();
getScreenShotAs(getClass().getName());
}
/**
* 检查注册失败情况 1
* 账号已存在
*/
@ParameterizedTest
@CsvSource({"张三,123,123"})
@Order(3)
void loginFail(String username, String password,String password2) throws InterruptedException, IOException {
// 登录之前先清空用户名和密码
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#password2")).clear();
// 登录步骤
driver.findElement(By.cssSelector("#username")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#password2")).sendKeys(password2);
driver.findElement(By.cssSelector("#submit")).click();
// 检测注册失败的场景
// 切换到弹窗, 进行弹窗的处理(隐式等待不生效,不得不加入强制等待)
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
// 警告弹窗
alert.accept();
getScreenShotAs(getClass().getName());
}
/**
* 检查注册失败情况 2
* 密码和确认密码不一致
* @param username
* @param password
* @param password2
* @throws InterruptedException
* @throws IOException
*/
@ParameterizedTest
@CsvSource({"小李,123,1234"})
@Order(4)
void loginFail2(String username, String password,String password2) throws InterruptedException, IOException {
// 登录之前先清空用户名和密码
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#password2")).clear();
// 登录步骤
driver.findElement(By.cssSelector("#username")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#password2")).sendKeys(password2);
driver.findElement(By.cssSelector("#submit")).click();
// 检测注册失败的场景
// 切换到弹窗, 进行弹窗的处理(隐式等待不生效,不得不加入强制等待)
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
// 警告弹窗
alert.accept();
getScreenShotAs(getClass().getName());
}
}
创建 BlogLoginTest 类, 该类的测试用例主要有 6 个 :
相关代码 :
// 登录页面
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogLoginTest extends AutoTestUtils {
public static EdgeDriver driver;
@BeforeAll
static void baseController() {
driver = getDriver();
driver.get("http://43.139.1.94:8080/login.html");
}
/**
* 检查登录页面是否正常打开
* 检查登录页的登录,用户名,密码等字样是否出现
*/
@Test
@Order(1)
void loginPageLoadRight() throws IOException {
driver.findElement(By.cssSelector("body > div.login-container > div > h3"));
driver.findElement(By.xpath("/html/body/div[2]/div/div[1]/span"));
driver.findElement(By.xpath("/html/body/div[2]/div/div[2]/span"));
getScreenShotAs(getClass().getName());
}
/**
* 检查正常登录的情况
* 页面是否显示用户名, 密码, 提交字样
*/
@ParameterizedTest
@CsvSource({"张三,123","李四,123"})
@Order(6)
void loginSuccess(String username,String password) throws IOException {
// 登录之前先清空用户名和密码
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
// 登录步骤
driver.findElement(By.cssSelector("#username")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#submit")).click();
// 检测登录结果 (检查我的列表页的查看详情按钮)
driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.mydetail > a:nth-child(1) > b"));
getScreenShotAs(getClass().getName());
// 一个用户测试完了,需要进行回退
driver.navigate().back();
}
/**
* 检查异常登录的情况 4 种情况 - 账号密码错误
* 账号密码错误, 会弹窗提示
*/
@ParameterizedTest
@CsvSource({"admin,345", "zhangsan,234"})
@Order(5)
void loginFail(String username, String password) throws InterruptedException, IOException {
// 登录之前先清空用户名和密码
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
// 登录步骤
driver.findElement(By.cssSelector("#username")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#submit")).click();
// 检测登录失败的场景
// 切换到弹窗, 进行弹窗的处理(隐式等待不生效,不得不加入强制等待)
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
// 警告弹窗
alert.accept();
getScreenShotAs(getClass().getName());
}
/**
* 未输入密码
* @param username
* @throws InterruptedException
*/
@ParameterizedTest
@ValueSource(strings = {"zhangsan"})
@Order(4)
void loginFail2(String username) throws InterruptedException, IOException {
// 登录之前先清空用户名和密码
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
// 登录步骤
driver.findElement(By.cssSelector("#username")).sendKeys(username);
driver.findElement(By.cssSelector("#submit")).click();
// 检测登录失败的场景
// 切换到弹窗, 进行弹窗的处理(隐式等待不生效,不得不加入强制等待)
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
// 警告弹窗
alert.accept();
getScreenShotAs(getClass().getName());
}
/**
* 未输入用户名
* @param password
* @throws InterruptedException
*/
@ParameterizedTest
@ValueSource(strings = {"123"})
@Order(3)
void loginFail3(String password) throws InterruptedException, IOException {
// 登录之前先清空用户名和密码
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
// 登录步骤
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#submit")).click();
// 检测登录失败的场景
// 切换到弹窗, 进行弹窗的处理(隐式等待不生效,不得不加入强制等待)
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
// 警告弹窗
alert.accept();
getScreenShotAs(getClass().getName());
}
/**
* 账号,, 密码都没有输入
* @throws InterruptedException
*/
@Test
@Order(2)
void loginFail4() throws InterruptedException, IOException {
driver.findElement(By.cssSelector("#submit")).click();
// 检测登录失败的场景
// 切换到弹窗, 进行弹窗的处理(隐式等待不生效,不得不加入强制等待)
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
// 警告弹窗
alert.accept();
getScreenShotAs(getClass().getName());
}
}
创建 MyBlogListTest 类, 该类的测试用例只有一个 :
相关代码 :
public class MyBlogListTest extends AutoTestUtils {
public static EdgeDriver driver;
// 创建驱动对象
@BeforeAll
static void baseController() {
driver = getDriver();
driver.get("http://43.139.1.94:8080/myblog_list.html");
}
/**
* 个人博客列表页可以正常显示
*/
@Test
void MyListPageLoadRight() throws IOException {
// 查看是否有删除按钮
driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.mydetail > a:nth-child(3) > b"));
driver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)"));
getScreenShotAs(getClass().getName());
}
}
创建 EveryBlogListTest 类, 该类的测试用例只有一个 :
相关代码 :
public class EveryBlogListTest extends AutoTestUtils {
public static EdgeDriver driver;
@BeforeAll
static void baseController() {
driver = getDriver();
driver.get("http://43.139.1.94:8080/blog_list.html");
}
/**
* 大家的列表页能否正常显示
* @throws IOException
*/
@Test
void everyListPageLoadRight() throws IOException {
driver.findElement(By.cssSelector("body > div.nav > a"));
driver.findElement(By.cssSelector("#listDiv > div:nth-child(1) > a"));
getScreenShotAs(getClass().getName());
}
}
创建 BlogEditTest 类, 该类的主要测试用例有 :
相关代码 :
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogEditTest extends AutoTestUtils {
public static EdgeDriver driver;
@BeforeAll
static void baseController() {
driver = getDriver();
driver.get("http://43.139.1.94:8080/blog_edit.html");
}
/**
* 检查博客编辑页可以正常打开
*/
@Test
@Order(1)
void editPageLoadRight() throws IOException {
// 检查正文中 "在这里写下一篇博客"
driver.findElement(By.cssSelector("#editorDiv > div.CodeMirror.cm-s-default.CodeMirror-wrap > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre"));
// 检查编辑器上的 H5 标题
driver.findElement(By.cssSelector("#editorDiv > div.editormd-toolbar > div > ul > li:nth-child(17) > a > i"));
getScreenShotAs(getClass().getName());
}
/**
* 测试填写博客标题, 博客正文, 是否能够正常发布博客
* @throws InterruptedException
* @throws IOException
*/
@Test
@Order(2)
void editAndSubmitBlog() throws InterruptedException, IOException {
String expect = "陈伟霆 vs 彭于晏";
driver.findElement(By.cssSelector("#title")).sendKeys(expect);
// 因博客系统使用到的编辑器是第三方插件, 所以不能直接使用 sendKeys 向编辑器发送文本,使用下划线,斜线代替
driver.findElement(By.cssSelector("#editorDiv > div.editormd-toolbar > div > ul > li:nth-child(21) > a > i")).click();
driver.findElement(By.cssSelector("#editorDiv > div.editormd-toolbar > div > ul > li:nth-child(6) > a > i")).click();
driver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();
// 获取我的列表页第一条博客的标题文本, 检查是否符合预期
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
alert.accept();
getScreenShotAs(getClass().getName());
String actual = driver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.title")).getText();
Assertions.assertEquals(expect,actual);
}
}
创建 BlogDetailTest 类, 该类的主要测试用例有 :
相关代码 :
public class BlogDetailTest extends AutoTestUtils{
public static EdgeDriver driver;
@BeforeAll
static void baseController() {
driver = getDriver();
driver.get("http://43.139.1.94:8080/blog_content.html?id=17");
}
/**
* 测试博客详情页显示是否符合预期
* @throws IOException
*/
@Test
void detailPageLoadRight() throws IOException {
driver.findElement(By.cssSelector("#title"));
driver.findElement(By.cssSelector("#date"));
getScreenShotAs(getClass().getName());
}
}
创建 RunSuite 类, 该类是用来指定哪些测试类需要运行, 以及运行顺序的.
@Suite
@SelectClasses({BlogRegTest.class,BlogLoginTest.class,
MyBlogListTest.class,EveryBlogListTest.class,
BlogEditTest.class,BlogDetailTest.class,DriverQuitTest.class})
public class RunSuite {
}
运行测试套件, 程序执行结果 :
屏幕截图结果 :
本篇文章就到这里了, 谢谢观看!!