一、项目背景
在线音乐服务器采用前后端分离的方法来实现,同时使用了数据库来存储相关的数据,同时将其部署到云服务器上。前端主要有个页面构成:登录页、音乐列表页、收藏音乐页等,以上模拟实现了最简单的在线音乐服务器。其结合后端实现了以下的主要功能:登录、上传音乐、播放音乐、查询音乐、删除音乐、收藏音乐、取消收藏音乐等功能。该音乐服务器可以实现用户简单的听音乐,收藏音乐等需求。
二、项目功能
在线音乐服务器主要实现了以下几个功能:登录、上传音乐、播放音乐、查询音乐、删除音乐、收藏音乐、取消收藏音乐等功能。
-
登录功能:用户输入用户名和密码,如果输入正确的用户名和密码则登录成功并跳转到个人博客列表页面;如果输入错误的用户名和密码则提示用户输入的信息有误,登录失败。
-
上传音乐功能:用户上传格式正确的音乐文件,以及填写音乐所属的歌手名,最终能成功上传到服务器保存。
-
播放音乐功能:用户点击播放音乐,音乐能够正常播放。
-
查询音乐功能:用户可以通过模糊查询和精确查询所要想搜索的音乐。
-
删除音乐功能:用户可以单个删除音乐,也可以通过勾选批量删除多个音乐。
-
收藏音乐功能:用户选择喜欢的音乐可进行收藏,成功收藏后可保存在个人收藏列表页。
-
展示收藏音乐功能:展示用户收藏的喜欢的音乐,并且能够进行正常的播放等操作。
-
取消收藏音乐功能:用户在收藏音乐的列表中可以选择删除取消收藏的音乐。
三、Web自动化测试
一)测试用例设计
二)代码编写
- 登录功能测试
① 创建驱动,并打开页面;
② 测试页面是否正常打开;
③ 测试正常登录:使用正确的用户名和密码进行等;
④ 测试异常登录:用户名/密码不正确,登录失败,多参数测试;
⑤ 注意测试的顺序,使用Order注解指定,否则可能会因为执行顺序不对导致测试失败;
⑥ 注意清空内容后才能再次输入用户名、密码。
package com.musicAutoTest.Tests;
import com.musicAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.*;
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.chrome.ChromeDriver;
import java.time.Duration;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LoginTest extends AutotestUtils {
private static ChromeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://localhost:8888/login.html");
}
/**
* 页面可以正常显示
*/
@Test
@Order(1)
void LoginLoadRight() {
driver.findElement(By.cssSelector("#body > div > div:nth-child(3) > label"));
driver.findElement(By.cssSelector("#body > div > div.alert.alert-warning.alert-dismissible"));
}
/**
* 正常登录
*/
@Test
@Order(3)
void LoginSuc() throws InterruptedException {
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
driver.findElement(By.cssSelector("#user")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#user")).sendKeys("shuai");
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.findElement(By.cssSelector("#submit")).click();
Thread.sleep(5);
Alert alert = driver.switchTo().alert();
alert.accept();
//检查是否登录成功
driver.findElement(By.cssSelector("#body > div.container > h3"));
driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3) > a:nth-child(1)"));
driver.navigate().back();
}
/**
* 异常登录
*/
@ParameterizedTest
@Order(2)
@CsvSource({"'',''","'',123","'',123","123,123"})
void LoginFail(String name, String password) throws InterruptedException {
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
driver.findElement(By.cssSelector("#user")).clear();
driver.findElement(By.cssSelector("#password")).clear();
driver.findElement(By.cssSelector("#user")).sendKeys(name);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.cssSelector("#submit")).click();
Thread.sleep(5);
Alert alert = driver.switchTo().alert();
alert.accept();
//检查是否登录没成功
driver.findElement(By.cssSelector("#body > div > div:nth-child(3) > label"));
driver.findElement(By.cssSelector("#body > div > div.alert.alert-warning.alert-dismissible"));
}
}
- 上传音乐功能测试
① 如若驱动已经创建好则不需再次创建驱动,打开页面;
② 测试页面是否正常打开;
③ 正常的上传,上传正确格式的音乐文件;
④ 测试异常上传:上传非音乐格式的文件。
package com.musicAutoTest.Tests;
import com.musicAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import java.time.Duration;
import java.util.List;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UploadMusicTest extends AutotestUtils {
private static ChromeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://localhost:8888/list.html");
}
/**
* 检查页面能否正常打开
*/
@Test
@Order(1)
void pageLoadRight() {
driver.findElement(By.cssSelector("#body > div.container > h3"));
driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3)"));
}
/**
* 上传音乐
*/
@Test
@Order(2)
void uploadSuc() {
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
List<WebElement> list1 = driver.findElements(By.name("tr"));
int count1 = list1.size();
driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3) > a:nth-child(2)")).click();
driver.findElement(By.cssSelector("body > form > input[type=file]:nth-child(1)")).sendKeys("C:/music.mp3");
driver.findElement(By.cssSelector("body > form > label > input[type=text]")).sendKeys("user");
driver.findElement(By.cssSelector("body > form > input[type=submit]:nth-child(3)")).click();
List<WebElement> list2 = driver.findElements(By.name("tr"));
int count2 = list2.size();
int suc = count2 - count1;
Assertions.assertEquals("1",suc+"");
}
}
- 播放音乐功能测试
① 如若驱动已经创建好则不需再次创建驱动,打开页面;
② 测试页面是否正常打开;
③ 点击播放音乐按钮;
④ 测试音乐是否播放,检查点为属性值。
package com.musicAutoTest.Tests;
import com.musicAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RunMusicTest extends AutotestUtils {
private static ChromeDriver driver = createDriver();
//打开页面
@BeforeAll
static void baseControl() {
driver.get("http://localhost:8888/list.html");
}
//页面能否正常显示
@Test
@Order(1)
void pageLoadRight() {
driver.findElement(By.cssSelector("#body > div.container > h3"));
driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3)"));
}
//能否正常播放音乐
@Test
@Order(2)
void runMusicSuc() {
driver.findElement(By.cssSelector("#info > tr:nth-child(1) > td:nth-child(4) > button")).click();
//检查点,属性值
String text = driver.findElement(By.cssSelector("#body > div:nth-child(2) > div > div > div.controlbar > ul > li:nth-child(1) > a")).getAttribute("style");
System.out.println(text);
Assertions.assertEquals("display: none;",text);
}
}
- 查询音乐功能
① 如若驱动已经创建好则不需再次创建驱动,打开页面;
② 测试页面是否正常打开;
③ 输入空字符进行查询;
④ 分别进行模糊查询和精确查询测试是否能查询到。
package com.musicAutoTest.Tests;
import com.musicAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import java.time.Duration;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SelectMusicTest extends AutotestUtils {
private static ChromeDriver driver = createDriver();
//打开页面
@BeforeAll
static void baseControl() {
driver.get("http://localhost:8888/list.html");
}
//页面能否正常显示
@Test
@Order(1)
void pageLoadRight() {
driver.findElement(By.cssSelector("#body > div.container > h3"));
driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3)"));
}
//精确查询
@Test
@Order(2)
void searchOne() {
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
driver.findElement(By.cssSelector("#exampleInputName2")).clear();
driver.findElement(By.cssSelector("#exampleInputName2")).sendKeys("music");
driver.findElement(By.cssSelector("#submit1")).click();
String text = driver.findElement(By.cssSelector("#info > tr > td:nth-child(2)")).getText();
Assertions.assertEquals("music",text);
}
//模糊查询
@Test
@Order(3)
void searchMore() {
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
driver.findElement(By.cssSelector("#exampleInputName2")).clear();
driver.findElement(By.cssSelector("#exampleInputName2")).sendKeys("mu");
driver.findElement(By.cssSelector("#submit1")).click();
String text = driver.findElement(By.cssSelector("#info > tr > td:nth-child(2)")).getText();
Assertions.assertEquals("music",text);
}
}
- 收藏音乐功能
① 如若驱动已经创建好则不需再次创建驱动,打开页面;
② 测试页面是否正常打开;
③ 点击收藏音乐,测试是否被收藏。
package com.musicAutoTest.Tests;
import com.musicAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LoveMusicTest extends AutotestUtils {
private static ChromeDriver driver = createDriver();
//打开页面
@BeforeAll
static void baseControl() {
driver.get("http://localhost:8888/list.html");
}
//页面能否正常显示
@Test
@Order(1)
void pageLoadRight() {
driver.findElement(By.cssSelector("#body > div.container > h3"));
driver.findElement(By.cssSelector("#body > div.container > div:nth-child(3)"));
}
//点击喜欢
@Test
@Order(2)
void loveMusicSuc() throws InterruptedException {
driver.findElement(By.cssSelector("#info > tr:nth-child(1) > td:nth-child(5) > button:nth-child(2)")).click();
Thread.sleep(5);
Alert alert = driver.switchTo().alert();
String text = alert.getText();
alert.accept();
Assertions.assertEquals("加入喜欢的列表成功",text);
}
//重复点击
@Test
@Order(3)
void loveMusicFail() throws InterruptedException {
driver.findElement(By.cssSelector("#info > tr:nth-child(1) > td:nth-child(5) > button:nth-child(2)")).click();
Thread.sleep(8);
Alert alert = driver.switchTo().alert();
String text = alert.getText();
alert.accept();
Assertions.assertNotEquals("加入喜欢的列表成功",text);
}
}
- 展示收藏音乐列表功能
① 如若驱动已经创建好则不需再次创建驱动,打开页面;
② 测试页面是否正常打开;
③ 测试刚收藏的音乐是否再列表中展示。
package com.musicAutoTest.Tests;
import com.musicAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
public class ShowLoveMusicTest extends AutotestUtils {
private static ChromeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://localhost:8888/loveMusic.html");
}
/**
* 展示收藏的音乐列表
*/
@Test
void showSuc() {
String text = driver.findElement(By.cssSelector("#info > tr > td:nth-child(2)")).getText();
Assertions.assertEquals("music",text);
}
}
- 取消收藏音乐功能
① 如若驱动已经创建好则不需再次创建驱动,打开页面;
② 测试页面是否正常打开;
③ 点击取消收藏音乐,检查音乐是否已经被移除收藏列表。
package com.musicAutoTest.Tests;
import com.musicAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
public class DeleteLoveMusicTest extends AutotestUtils {
private static ChromeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://localhost:8888/loveMusic.html");
}
/**
* 取消收藏的音乐
*/
@Test
void deleteLoveMusic() {
List<WebElement> list = driver.findElements(By.name("#tr"));
int count1 = list.size();
driver.findElement(By.cssSelector("#info > tr > td:nth-child(5) > button")).click();
//统计数量
List<WebElement> list2 = driver.findElements(By.name("tr"));
int count2 = list2.size();
//再统计数量
int suc = count1 - count2;
Assertions.assertEquals("1",suc+"");
}
}
- 删除音乐功能
① 如若驱动已经创建好则不需再次创建驱动,打开页面;
② 测试页面是否正常打开;
③ 点击删除音乐,检查音乐是否被删除。
package com.musicAutoTest.Tests;
import com.musicAutoTest.common.AutotestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DeleteMusicTest extends AutotestUtils {
private static ChromeDriver driver = createDriver();
@BeforeAll
static void baseControl() {
driver.get("http://localhost:8888/loveMusic.html");
}
/**
* 删除音乐
*/
@Test
void deleteMusic() {
List<WebElement> list = driver.findElements(By.name("#tr"));
int count1 = list.size();
driver.findElement(By.cssSelector("#info > tr:nth-child(1) > td:nth-child(5) > button:nth-child(1)")).click();
//统计数量
List<WebElement> list2 = driver.findElements(By.name("tr"));
int count2 = list2.size();
//再统计数量
int suc = count1 - count2;
Assertions.assertEquals("1",suc+"");
}
}
- 屏幕截图
/**
* 动态生成时间
*/
public List<String> getTime() {
//文件夹按照天的维度进行保存
//文件格式 20240109-123030
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyyMMdd");
String filename = simpleDateFormat1.format(System.currentTimeMillis());
String dirname = simpleDateFormat2.format(System.currentTimeMillis());
List<String> list = new ArrayList<>();
list.add(dirname);
list.add(filename);
return list;
}
/**
* 获取屏幕截图,把所有的测试用例执行的结果保存下来
*/
public void getScreenShor(String str) throws IOException {
List<String> list = getTime();
//dir+filename
// ./src/test/java/com/blogWebAutoTest/dirname/filename
String fileName = "./src/test/java/com/blogWebAutoTest/"+list.get(0) + "/" + str + "-" + list.get(1) + ".png";
File srcfile = driver.getScreenshotAs(OutputType.FILE);
//把屏幕截图生成的文件放到指定的路径
FileUtils.copyFile(srcfile,new File(fileName));
String filename = "my";
}
三)代码测试
四、总结
- 使用了Junit5中提供的注解:避免生成过多的对象,造成资源和时间的浪费,提高了自动化的执行效率。
- 只创建一次驱动对象,避免每个用例重复创建驱动对象造成时间和资源的浪费。
- 使用参数化:保持用例的简洁,提高代码的可读性。
- 使用测试套件:降低了测试人员的工作量,通过套件一次执行所有要运行的测试用例。
- 使用了等待:提高了自动化的运行效率,提高了自动化的稳定性,减小误报的可能性。
- 使用了屏幕截图:方便问题的追溯以及问题的解决。
- 使用了无头模式:只注重结果,可以留出屏幕。