目录
一、项目背景
这是一个基础版本的在线音乐播放网站,用户可以上传音乐,在线聆听已上传的音乐。
同时支持用户将指定音乐添加到自己喜欢列表。
项目地址:音乐播放器登录页面
项目代码:gitee地址
二、项目功能
1、登录功能——用户可按正常的用户名和密码进行登录,进入到音乐列表页面
2、注册功能——未注册的用户可以按照进行注册,设定自己的用户名和密码进行登录
3、音乐列表页面——用户可实时查看当前网站所有上传的音乐,提供音乐播放、音乐收藏和音乐删除功能,此外该页面还提供了音乐搜索和分页显示音乐列表的功能。
tips: 我们目前并没有提供权限模块,用户默认都是管理员,可以进行音乐的上传和删除功能
4、音乐收藏页面——用户可查看当前自己所收藏的所有上传音乐,并进行音乐的播放。
5、音乐上传——用户可上传本地音乐到服务器,同时系统会将该音乐相关信息存储到对应数据库中
6、音乐播放——借助SewisePlayer播放插件实现对用户上传音乐的播放
三、功能测试
1、登录页面的测试
测试用例
测试结果
1)页面显示
图片显示有问题
经查是前端页面显示该图片的过程中出现了问题(路径错误)
解决后如下
2)正常登录
3)异常登录
2、注册页面的测试
测试用例
测试结果
1)页面显示
2)正常注册
3)异常注册
3、音乐列表页面的测试
测试用例
测试结果
1)页面效果
2)功能模块
分页功能
播放功能
出现的bug
搜索功能的bug
输入英文、字母搜索是正常
但是一旦输入汉字搜索会出现乱码现象,并且找不到要搜索的内容
问题解决
当一个问题出现,首先要确定这个是前端的问题还是后端的问题,我们先来看浏览器上的显示
是前端传递参数错误吗,但是在开发者工具中明明就前端就是想后端传递了对应的title值,同时前端也设置了字符编码
那么我们就先从后端入手
我们尝试动进行URL解码来处理中文乱码问题
这个时候,我们发现前端仍然有问题
我们在前端在查询url中的某个参数值的时候,再对参数值进行解密——以应对上面的这种情况
可以看到,成功再搜索框中显示了当前搜索的关键字,但是这样做有一个问题,那就是歌曲名这个信息直接暴漏在url中
删除功能的bug
如果当前用户为登录,会出现弹窗,提示跳转到登录页面
问题解决
出现了bug,首先我们来想怎么解决这个bug
首先来确定bug的位置
通过上图我们可以看到,我们前端想后端成功传递了要删除的音乐id,但是后端没有返回预期的结果,后端在音乐删除过程中出错了
我们注意到后端代码中红框这一行,我们在音乐表删除对应记录的时候,同时还想要同步删除喜欢列表中该音乐所对应记录
但是这样有一个问题,如果在喜欢列表中没有该音乐所对应的记录,此时res2 不就等于0,此时不就会出现问题吗?
并且,通过观察喜欢列表后,我们发现喜欢列表的数据也是根据音乐表产生了,是一个多表查询,因此我们在删除音乐表中的对应记录的时候,不用把喜欢列表的记录给同步删除。
下面是修改后的
4、喜欢列表页面的测试
测试用例
测试结果
5、上传音乐页面的的测试
测试用例
测试结果
页面效果
异常上传
正常上传
四、自动化测试
📝概述
自动化测试代码:gitee地址
1、登录注册页面
测试点
测试代码
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.chrome.ChromeDriver;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 指定类的测试顺序
public class LoginTest extends AutoTest {
// 这里我们调用了父类AutoTest中的静态方法,获取驱动对象
public static ChromeDriver driver = createDriver();
@Test
@BeforeAll // 被@BeforeAll修饰的方法要是静态的
static void init() {
// 跳转到博客登录页面
driver.get("http://49.235.66.46:9090/login.html");
driver.manage().window().maximize();
}
// 检查登录页面显示是否正常
@Test
@Order(1)
void loginPageTest() {
String expect = "登录";
String actual = driver.findElement(By.xpath("/html/body/div[2]/div/h3")).getText();
// 通过断言查看页面显示
Assertions.assertEquals(expect, actual);
// 查看页面相关元素是否存在
driver.findElement(By.cssSelector("#submit"));
driver.findElement(By.cssSelector("body > div.nav > a"));
Assertions.assertEquals("音乐播放器", driver.findElement(By.cssSelector("body > div.nav > span.title")).getText());
}
// 检查用户名密码出错的情况(登录失败的情况)
@Order(2)
@ParameterizedTest // 多个参数
@CsvSource({"admin, 123"})
void loginFailTest(String username, String password) throws InterruptedException {
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();
Assertions.assertEquals("登录失败,密码或者用户名错误!", alert.getText());
alert.accept();
}
// 检查用户名或者密码错误(登录成功的情况)
@Order(3)
@ParameterizedTest // 多个参数
@CsvSource({"小鱼儿, 123"})
void loginSuccessfulTest(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(200);
Alert alert = driver.switchTo().alert();
Assertions.assertEquals("登录成功!", alert.getText());
alert.accept();
// 上述步骤只是说明输入了账号和密码,但还不知道点击提交后是否会跳转到音乐列表页
String expect = "http://49.235.66.46:9090/list.html";
String actual = driver.getCurrentUrl();
Assertions.assertEquals(expect, actual); // 查看当前的url是否音乐列表页面
// 进行截图,看当前是否跳转到了音乐列表界面
// 程序执行的速度和页面渲染的速度
File srcFile = driver.getScreenshotAs(OutputType.FILE);
String fileName = "loginRightTest.png";
FileUtils.copyFile(srcFile, new File(fileName));
}
@AfterAll
@Test
static void exit() {
driver.quit();
}
}
测试结果
音乐播放器--登录页面自动化测试
2、音乐总列表页面
测试点
测试代码
package loginedTests;
import common.AutoTest;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.chrome.ChromeDriver;
import java.io.File;
import java.io.IOException;
/**
* 登录情况下
* 音乐总列表页面的测试
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 指定类的测试顺序(根据每个方法的order序号)
public class musicList extends AutoTest {
public static ChromeDriver driver = createDriver();
@Test
@BeforeAll
static void init() {
driver.get("http://49.235.66.46:9090/list.html?pindex=1&name=");
driver.manage().window().maximize();
}
@Test
@Order(1)
void pageTest() { // 检查页面显示和音乐播放功能
// 跳转后的新页面的文字显示
Assertions.assertEquals("音乐列表", driver.findElement(By.cssSelector("#body > div.container > h3")).getText());
// 查看播放悬浮框是否存在
driver.findElement(By.cssSelector("#body > div:nth-child(3) > div > div > div.big-play-btn > a"));
Assertions.assertEquals("喜欢列表", driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3) > a:nth-child(1)")).getText());
Assertions.assertEquals("添加歌曲", driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3) > a:nth-child(2)")).getText());
Assertions.assertEquals("删除选中", driver.findElement(By.cssSelector("#delete")).getText());
Assertions.assertEquals("退出登录", driver.findElement(By.cssSelector("#logout")).getText());
// 各个链接、按钮,能否正常跳转到对应页面
// driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3) > a:nth-child(1)")).click();
// String expectUrl1 = "http://49.235.66.46:9090/loveMusic.html";
// Assertions.assertEquals(expectUrl1, driver.getCurrentUrl());
// driver.navigate().back(); // 回退到音乐列表页面
driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3) > a:nth-child(2)")).click();
String expectUrl = "http://49.235.66.46:9090/upload.html";
Assertions.assertEquals(expectUrl, driver.getCurrentUrl());
driver.navigate().back();
// 检查音乐播放功能
// 获取第一首歌曲的播放按钮元素,点击播放
driver.findElement(By.cssSelector("#info > tr:nth-child(1) > td:nth-child(4) > button")).click();
String expectSrc = "http://jackzhang1204.github.io/materials/where_did_time_go.mp3";
String actualSrc = driver.findElement(By.cssSelector("#body > div:nth-child(3) > div > audio")).getAttribute("src");
// 默认未点击播放的src值为:http://jackzhang1204.github.io/materials/where_did_time_go.mp3
// 如果正常播放:比如当前页面的第一个个歌曲——此时src的值 :http://49.235.66.46:9090/music/get?path=%E5%BC%80%E5%A7%8B%E6%87%82%E4%BA%86-%E5%AD%99%E7%87%95%E5%A7%BF.128.mp3
Assertions.assertNotEquals(expectSrc,actualSrc); // 如果不匹配,说明音乐可以正常播放
}
@Test
@Order(2) // 分页功能测试
void pagingTest() throws InterruptedException {
// 先点击首页功能,因为我们本来就是在首页 ,页面地址没有发生变化
String expectUrl1 = driver.getCurrentUrl();
driver.findElement(By.cssSelector("#all > li:nth-child(1) > a")).click();
String actualUrl1 = driver.getCurrentUrl();
Assertions.assertEquals(expectUrl1, actualUrl1);
// 接着点击上一页,查看页面的变化(因为此时我们已经是第一页了,所有会出现提示弹窗)
driver.findElement(By.cssSelector("#all > li:nth-child(2) > a")).click();
// 因为我们musicList继承了AutoTest父类,父类中隐式等待作用范围仍然包括这部分
// 但是我们弹窗不属于HTML元素,隐式等待无法生效,我们这样需要强制等待
Thread.sleep(100);
Alert alert = driver.switchTo().alert();
Assertions.assertEquals("已经是首页了", alert.getText());
alert.accept();
// 点击下一页(查看点击后,跳转的地址是否正确)
driver.findElement(By.cssSelector("#all > li:nth-child(3) > a")).click();
String expect = "http://49.235.66.46:9090/list.html?pindex=2&name=";
Assertions.assertEquals(expect, driver.getCurrentUrl());
// 末页元素的查看
driver.findElement(By.cssSelector("#all > li:nth-child(4) > a"));
}
@Test
@Order(3)// 搜索功能测试
void searchTest() throws IOException, InterruptedException {
// 往搜索框中输入文本,点击搜索,查看页面是否出现你要找的搜索结果(按歌曲名称查找)
driver.findElement(By.cssSelector("#exampleInputName2")).sendKeys("开始懂了");
driver.findElement(By.cssSelector("#submit1")).click();
// 进行截图,看当前是否跳转到了登录界面
// 程序执行的速度和页面渲染的速度
File srcFile = driver.getScreenshotAs(OutputType.FILE);
String fileName = "searchTest.png";
FileUtils.copyFile(srcFile, new File(fileName));
// 如果搜索到了,应该能找到对应的歌手
String expect = "孙燕姿";
Assertions.assertEquals(expect, driver.findElement(By.cssSelector("#info > tr > td:nth-child(3)")).getText());
// 如果搜索结果为空,是否有弹窗提醒
driver.findElement(By.cssSelector("#exampleInputName2")).clear();
driver.findElement(By.cssSelector("#exampleInputName2")).sendKeys("ddf懂了");
driver.findElement(By.cssSelector("#submit1")).click();
Thread.sleep(200);
Alert alert = driver.switchTo().alert();
Assertions.assertEquals("当前搜索结果为空,请重新搜索", alert.getText());
alert.accept();
}
@AfterAll
@Test
static void exit() {
driver.quit();
}
}
测试结果
音乐播放器音乐总列表页面自动化测试
3、音乐收藏页面
测试点
测试代码
package loginedTests;
import common.AutoTest;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
import javax.swing.tree.TreeNode;
import java.io.File;
import java.io.IOException;
import java.util.List;
import static loginedTests.LoginTest.driver;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 指定类的测试顺序(根据每个方法的order序号)
public class myMusicListTest extends AutoTest {
// 这里我们调用了父类AutoTest中的静态方法,获取驱动对象
// public static ChromeDriver driver = createDriver();
// 我们这里不用重新生成驱动,用的还是登录页面的驱动
@Test
@BeforeAll // 被@BeforeAll修饰的方法要是静态的
static void init() {
// 跳转到博客登录页面
driver.get("http://49.235.66.46:9090/loveMusic.html");
// driver.manage().window().maximize();
}
// 返回当前页面是否存在弹窗
private boolean isAlertPresent(WebDriver driver) {
try {
driver.switchTo().alert();
return true;
} catch (NoAlertPresentException e) {
return false;
}
}
/**
* 检查页面显示和各个按钮所对应的功能(音乐播放,从收藏列表中移除该元素)
*/
@Test
@Order(1)
void lovePageTest() throws InterruptedException, IOException {
/**
* 判断是否有弹窗,如果当前收藏列表为空,会出现弹窗提示
*/
// 初始化 WebDriverWait 对象
// WebDriverWait 类来设置等待时间为3秒,并使用 until() 方法结合 ExpectedConditions.alertIsPresent() 来等待弹窗的出现。
// 如果在等待时间内成功找到弹窗,until() 方法返回一个 Alert 对象;否则,返回 null。然后,我们将 Alert 对象与 null 进行比较,以判断弹窗是否存在。
File srcFile1 = driver.getScreenshotAs(OutputType.FILE);
String fileName1 = "myMusicListTest.png";
FileUtils.copyFile(srcFile1, new File(fileName1));
Duration timeout = Duration.ofSeconds(3); // 设立弹窗轮询查看时间
boolean isAlert = isAlertPresent(driver);
WebDriverWait wait = new WebDriverWait(driver, timeout);
try {
// 等待弹窗出现---如果出现弹窗,说明当前收藏(喜欢)列表为空,就不执行接下来的测试步骤,直接返回
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
System.out.println("弹窗内容:" + alert.getText());
alert.accept();
return;
} catch (TimeoutException e) {
// 异常处理:超时未出现弹窗--收藏(喜欢列表)不为空
System.err.println("等待弹窗超时");
}
String expect = "我喜欢的音乐列表";
String actual = driver.findElement(By.cssSelector("body > div.container > h3")).getText();
Assertions.assertEquals(expect, actual);
// 查看页面相关元素是否存在,文本是否一致
Assertions.assertEquals("回到首页", driver.findElement(By.cssSelector("body > div.container > div:nth-child(3) > a.btn.btn-primary")).getText());
Assertions.assertEquals("退出登录", driver.findElement(By.cssSelector("#logout")).getText());
// 搜索框和搜索按钮
driver.findElement(By.cssSelector("#exampleInputName2"));
Assertions.assertEquals("查询", driver.findElement(By.cssSelector("#submit1")).getText());
// 查看播放悬浮框是否存在
driver.findElement(By.cssSelector("body > div:nth-child(3) > div"));
// 检查音乐播放功能
//
// 获取第一首歌曲的播放按钮元素,点击播放
driver.findElement(By.cssSelector("#info > tr:nth-child(1) > td:nth-child(3) > button")).click();
String expectSrc = "http://jackzhang1204.github.io/materials/where_did_time_go.mp3";
String actualSrc = driver.findElement(By.cssSelector("body > div:nth-child(3) > div > audio")).getAttribute("src");
// 默认未点击播放的src值为:http://jackzhang1204.github.io/materials/where_did_time_go.mp3
// 如果正常播放:比如当前页面的第一个个歌曲——此时src的值 :http://49.235.66.46:9090/music/get?path=%E5%BC%80%E5%A7%8B%E6%87%82%E4%BA%86-%E5%AD%99%E7%87%95%E5%A7%BF.128.mp3
Assertions.assertNotEquals(expectSrc,actualSrc); // 如果不匹配,说明音乐可以正常播放
/**
* 从音乐列表中移除该元素(移除 列表中的第三首歌)
*/
// 移除前,喜欢列表的歌曲数目 = 移除后,喜欢列表的歌曲数目 + 1;
// // 定位歌曲表格
WebElement table = driver.findElement(By.cssSelector("body > div.container > table"));
// 定位歌曲行元素
List<WebElement> songRows = table.findElements(By.tagName("tr"));
// 获取歌曲数量
int songCount = songRows.size() - 1; //减去表格的头部
System.out.println("移除前,当前页面歌曲的数目:" + songCount);
// 移除元素--移除元素
WebElement elementPlay;
try {
elementPlay = driver.findElement(By.cssSelector("#info > tr:nth-child(3) > td:nth-child(4) > button"));
} catch (Exception e) {
System.err.println("你要移除的元素不存在!!!");
return; // // 如果要移除的元素(歌曲),没有显示在列表中(或者已经移除),出现异常,直接返回
}
System.out.println("从而达到是");
elementPlay.click();
/**
* 我们获取弹窗的时候,最好都try catch一下,这样更保险,处理因为找不到弹窗而出现的异常
*/
// 会出现一个弹窗,提示是否要移除该元素
try {
Alert alert2 = driver.switchTo().alert();
alert2.accept();
}
catch (TimeoutException e) {
// 异常处理:超时未出现弹窗
System.err.println("等待弹窗超时");
}
// 点击,确定,系统会处理这个操作,从数据库的喜欢列表中移除该元素,这是需要时间的,所有需要等待弹窗的出现
// 移除后,有会出现一个弹窗,提示移除成功
try {
Alert alert3 = wait.until(ExpectedConditions.alertIsPresent());
alert3.accept();
File srcFile4 = driver.getScreenshotAs(OutputType.FILE);
String fileName4 = "moveResultTest.png";
FileUtils.copyFile(srcFile4, new File(fileName4));
}
catch (TimeoutException e) {
// 异常处理:超时未出现弹窗
System.err.println("等待弹窗超时");
}
// 删除后,重新计算歌曲数量
WebElement tableNew = driver.findElement(By.cssSelector("body > div.container > table"));
// 定位歌曲行元素
songRows = tableNew.findElements(By.tagName("tr"));
// 获取歌曲数量
int songCountNew = songRows.size() - 1; //减去表格的头部
System.out.println("移除后,当前页面歌曲的数目:" + songCountNew);
Assertions.assertEquals(songCount, songCountNew + 1);
}
/**
* 搜索功能测试
* @throws IOException
* @throws InterruptedException
*/
@Test
@Order(2)
void searchTest() throws IOException, InterruptedException {
// 往搜索框中输入文本,点击搜索,查看页面是否出现你要找的搜索结果(按歌曲名称查找)
driver.findElement(By.cssSelector("#exampleInputName2")).sendKeys("开始懂了");
driver.findElement(By.cssSelector("#submit1")).click();
// 等待弹窗出现
Duration timeout = Duration.ofSeconds(3);
WebDriverWait wait = new WebDriverWait(driver, timeout);
// 尝试获取弹窗
// 我们在输入框中输入文本内容,点击查询,看是否出现弹窗
// 如果出现弹窗,说明搜索结果为空————直接返回
try {
Alert alert4 = wait.until(ExpectedConditions.alertIsPresent());
alert4.accept();
return;
}
catch (TimeoutException e) {
// 异常处理:超时未出现弹窗
System.err.println("等待弹窗超时");
}
// 程序走到这里,说明上面点击搜索后----没有弹窗————搜索结果不为空
System.out.println("No Alert Found.");
// 搜索结果截图
File srcFile = driver.getScreenshotAs(OutputType.FILE);
String fileName = "searchResultTest.png";
FileUtils.copyFile(srcFile, new File(fileName));
// 如果按歌曲名搜索到了,应该能找到该歌曲名所对应的歌手
String expect = "孙燕姿";
Assertions.assertEquals(expect, driver.findElement(By.cssSelector("#info > tr > td:nth-child(2)")).getText());
}
}
测试结果
一些思考点
关于等待弹窗
应对一些特殊情况,比如
1、喜欢(收藏)列表为空
2、搜索结果为空
往往需要等待弹窗,并根据弹窗提示,做相应的处理(避免找不到对应的元素 或出现异常)
这里我们采用
WebDriverWait对象的until()方法 + ExpectedConditions.alertIsPresent()来进行等待弹窗的出现——同时调用了自定义的isAlertPresent函数验证是否有弹窗出现
// 返回当前页面是否存在弹窗
private boolean isAlertPresent(WebDriver driver) {
try {
driver.switchTo().alert();
return true;
} catch (NoAlertPresentException e) {
return false;
}
}
/**
* 判断是否有弹窗,如果当前收藏列表为空,会出现弹窗提示
*/
// 初始化 WebDriverWait 对象
// WebDriverWait 类来设置等待时间为3秒,并使用 until() 方法结合 ExpectedConditions.alertIsPresent() 来等待弹窗的出现。
// 如果在等待时间内成功找到弹窗,until() 方法返回一个 Alert 对象;否则,返回 null。然后,我们将 Alert 对象与 null 进行比较,以判断弹窗是否存在。
File srcFile1 = driver.getScreenshotAs(OutputType.FILE);
String fileName1 = "myMusicListTest.png";
FileUtils.copyFile(srcFile1, new File(fileName1));
Duration timeout = Duration.ofSeconds(3); // 设立弹窗轮询查看时间
boolean isAlert = isAlertPresent(driver);
WebDriverWait wait = new WebDriverWait(driver, timeout);
try {
// 等待弹窗出现---如果出现弹窗,说明当前收藏(喜欢)列表为空,就不执行接下来的测试步骤,直接返回
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
System.out.println("弹窗内容:" + alert.getText());
alert.accept();
return;
} catch (TimeoutException e) {
// 异常处理:超时未出现弹窗--收藏(喜欢列表)不为空
System.err.println("等待弹窗超时");
}
关于音乐数量统计
将指定音乐从喜欢列表中移除
判断移除前后,当前页面的歌曲数目,变化
/**
* 从音乐列表中移除该元素(移除 列表中的第三首歌)
*/
// 移除前,喜欢列表的歌曲数目 = 移除后,喜欢列表的歌曲数目 + 1;
// // 定位歌曲表格
WebElement table = driver.findElement(By.cssSelector("body > div.container > table"));
// 定位歌曲行元素
List<WebElement> songRows = table.findElements(By.tagName("tr"));
// 获取歌曲数量
int songCount = songRows.size() - 1; //减去表格的头部
System.out.println("移除前,当前页面歌曲的数目:" + songCount);
// 移除元素--移除元素
WebElement elementPlay;
try {
elementPlay = driver.findElement(By.cssSelector("#info > tr:nth-child(3) > td:nth-child(4) > button"));
} catch (Exception e) {
System.err.println("你要移除的元素不存在!!!");
return; // // 如果要移除的元素(歌曲),没有显示在列表中(或者已经移除),出现异常,直接返回
}
System.out.println("从而达到是");
elementPlay.click();
/**
* 我们获取弹窗的时候,最好都try catch一下,这样更保险,处理因为找不到弹窗而出现的异常
*/
// 会出现一个弹窗,提示是否要移除该元素
try {
Alert alert2 = driver.switchTo().alert();
alert2.accept();
}
catch (TimeoutException e) {
// 异常处理:超时未出现弹窗
System.err.println("等待弹窗超时");
}
// 点击,确定,系统会处理这个操作,从数据库的喜欢列表中移除该元素,这是需要时间的,所有需要等待弹窗的出现
// 移除后,有会出现一个弹窗,提示移除成功
try {
Alert alert3 = wait.until(ExpectedConditions.alertIsPresent());
alert3.accept();
File srcFile4 = driver.getScreenshotAs(OutputType.FILE);
String fileName4 = "moveResultTest.png";
FileUtils.copyFile(srcFile4, new File(fileName4));
}
catch (TimeoutException e) {
// 异常处理:超时未出现弹窗
System.err.println("等待弹窗超时");
}
// 删除后,重新计算歌曲数量
WebElement tableNew = driver.findElement(By.cssSelector("body > div.container > table"));
// 定位歌曲行元素
songRows = tableNew.findElements(By.tagName("tr"));
// 获取歌曲数量
int songCountNew = songRows.size() - 1; //减去表格的头部
System.out.println("移除后,当前页面歌曲的数目:" + songCountNew);
Assertions.assertEquals(songCount, songCountNew + 1);
4、音乐上传页面
package loginedTests;
import common.AutoTest;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import java.io.File;
import java.io.IOException;
import static loginedTests.loginTest.driver;
/**
* 登录状态,对音乐上传页面的自动化测试
*/
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 指定类的测试顺序(根据每个方法的order序号)
public class musicUpload extends AutoTest {
// 这里我们调用了父类AutoTest中的静态方法,获取驱动对象
// public static ChromeDriver driver = createDriver();
// 我们这里不用重新生成驱动,用的还是登录页面的驱动
@Test
@BeforeAll // 被@BeforeAll修饰的方法要是静态的
static void init() {
// 跳转到博客登录页面
driver.get("http://49.235.66.46:9090/upload.html");
// driver.manage().window().maximize();
}
/**
* 检查页面显示、按钮
*/
@Test
@Order(1)
void uploadPageTest() throws IOException, InterruptedException {
File srcFile = driver.getScreenshotAs(OutputType.FILE);
String fileName = "musicUploadTest.png";
FileUtils.copyFile(srcFile, new File(fileName));
Assertions.assertEquals("音乐上传", driver.findElement(By.cssSelector("#uploadForm > h2")).getText());
Assertions.assertEquals("选择文件:", driver.findElement(By.cssSelector("#uploadForm > div:nth-child(2) > span")).getText());
Assertions.assertEquals("歌手名字:", driver.findElement(By.cssSelector("#uploadForm > div:nth-child(4) > span.text-form")).getText());
// 未选择文件和输入歌手名,点击上传
driver.findElement(By.cssSelector("#uploadForm > input[type=button]")).click();
Thread.sleep(150);
// 查看是否有弹窗
Alert alert = driver.switchTo().alert();
Assertions.assertEquals("请输入歌曲的作者", alert.getText());
alert.accept();
}
@Test
@AfterAll
static void exit() {
driver.quit();
}
}
自动化测试视频演示
音乐播放器-登录状态--总测试
自动化测试过程中遇到的bug
bug1
这里一开始我是很疑惑的,因为在对登录页面进行自动化测试的过程中,这个测试类是继承了一个公共类(该类中进行了隐式等待)
【另外, 隐式等待 作用于 WebDriver 整个生命周期】
【只要没有走到 driver.quit,即没有退出浏览器,隐式等待都是一直存在的】所以我们之后要写的登录界面只要继承的隐式等待,自然也能够使得测试登录界面的代码能够稍微停顿一下,等页面渲染完成
那么这里为什么还会显示找不到弹窗这个元素呢?
因为弹窗属于非HTML页面的元素,当时我在写的时候没有注意到这一点。
隐式等待是作用不了非HTML页面的元素的,所以弹窗无法等待,看下是否在切换到弹窗之前弹窗还没有出现,终端报的错误是不是noalert
那么我们用其他等待方式来在这里等待一下弹窗的出现
但是其中的依赖一旦换成compile,就可以了,
bug2
在对页面操作的过程中,我们往往要根据情况处理不同的异常
1、等待超时
程序在等待 alert 弹窗的出现时超时了,因此抛出了
TimeoutException
异常情况可能是:
页面上没有弹窗出现,因此
WebDriverWait
等待了 3 秒后仍未找到弹窗,于是抛出了超时异常。页面上的弹窗出现时间大于 3 秒,因此
WebDriverWait
在等待期间未能找到弹窗,于是抛出了超时异常。
不管是那种,我们都要处理这种异常
2、找不到对应的元素
这里是我们移除,收藏(喜欢列表)中第三首歌曲,但可能我们的收藏歌曲就不到三首,或者已经移除过该歌曲了,但页面没有及时刷新——这样就会出现问题
因此,我们在查找(获取)一些可能会出现问题的元素的时候,我们需要进行try catch进行一些异常的判断和处理