1.脑图展示自动化测试案例
2. 项目准备工作
① 创建一个Maven项目
② 创建BlogTest包存放自动化测试的代码文件,在这基础上创建两个包common跟Tests。
导入项目的依赖
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite -->
<!--使用suite必须用到 engine 引擎-->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.9.1</version>
</dependency>
3. 根据设计图设计自动化测试
3.1 创建工具类AutoTestUtils
目的是为了代码的复用,子类继承父类。在父类里写测试前的方法跟测试后的方法。
public class AutoTestUtils {
// 创建驱动
public static WebDriver webDriver;
// 类测试开始前
@BeforeAll
static void SetUp(){
webDriver=new ChromeDriver();
}
// 类测试结束后
@AfterAll
static void TearDown(){
// 退出浏览器
webDriver.quit();
}
// 屏幕截图, 保存文件的格式
public List<String> 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<String> list = new ArrayList<>();
list.add(dirname);
list.add(filename);
return list;
}
// 屏幕截图的方法
public void getScreenShotAs(String str) throws IOException {
List<String> list = getTime();
String filePath = "./src/test/blogTest/"+list.get(0)+"/"+str+"_"+list.get(1)+".png";
File srcFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcFile, new File(filePath));
}
}
3.2 测试个人博客的注册页
创建registTest类,使用到的测试用例有4个:
1. 注册页面是否正常打开
2. 输入用户名,密码,确认密码,用户是第一次注册,密码跟确认密码一致。(正确输入)
3. 输入用户名,密码,确认密码,用户不是第一次注册。(错误输入)
4. 输入用户名,密码,确认密码,用户是第一次注册,密码跟确认密码不一致。(错误输入)
代码实现:
// 设置优先级
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class registTest extends AutoTestUtils {
// 检查是否能正常打开注册页面
// 检查各个输入框是否出现
@Order(1)
@Test
void registPageLoadRight() throws IOException, InterruptedException {
// 打开注册页面
webDriver.get("http://localhost:8081/reg.html");
webDriver.findElement(By.cssSelector("#username"));
webDriver.findElement(By.cssSelector("#password"));
webDriver.findElement(By.cssSelector("#password2"));
webDriver.findElement(By.cssSelector("#code_input"));
sleep(1000);
getScreenShotAs(getClass().getName());
}
// 注册成功情况
@Order(2)
@ParameterizedTest
@CsvSource({"testUser,123456,123456"})
void registSuccess(String username,String password,String rePassword) throws InterruptedException, IOException {
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#password2")).sendKeys(rePassword);
sleep(6000);
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
// 截图
getScreenShotAs(getClass().getName());
}
// 注册失败
// 用户已存在
@Order(3)
@ParameterizedTest
@CsvSource({"testUser,123456,123456"})
void registFail(String username,String password,String rePassword) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/reg.html");
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#password2")).sendKeys(rePassword);
sleep(6000);
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(3000);
Alert alert=webDriver.switchTo().alert();
alert.dismiss();
// 截图
getScreenShotAs(getClass().getName());
}
// 注册失败
// 密码跟确认密码不一致
@Order(4)
@ParameterizedTest
@CsvSource({"testUser,123456,1234567"})
void registFail2(String username,String password,String rePassword) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/reg.html");
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#password2")).sendKeys(rePassword);
sleep(6000);
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(3000);
Alert alert=webDriver.switchTo().alert();
alert.dismiss();
// 截图
getScreenShotAs(getClass().getName());
}
}
3.3 测试个人博客的登录页面
创建loginTest类,使用到的测试用例有5个:
1. 注册页面是否正常打开
2. 输入用户名 userTest1 密码 123456 (未注册)
3. 输入用户名 userTest (未输入密码)
4. 输入用户名 userTest 密码 1234567 (密码错误)
5. 输入用户名 userTest 密码 123456 (输入正确)
代码实现:
// 设置优先级
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class loginTest extends AutoTestUtils {
@Order(1)
void loginPage() throws IOException {
webDriver.get("http://localhost:8081/login.html");
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
WebElement pwd=webDriver.findElement(By.cssSelector("#password"));
// 截图
getScreenShotAs(getClass().getName());
}
// 未注册
@Order(2)
@ParameterizedTest
@CsvSource("testUser1,123456")
void failLogin1(String username,String password) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/login.html");
// 输入账号
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
userName.sendKeys(username);
// 输入密码
WebElement pwd=webDriver.findElement(By.cssSelector("#password"));
pwd.sendKeys(password);
sleep(6000);
// 点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
// 截图
getScreenShotAs(getClass().getName());
}
// 未输入密码
@Order(3)
@ParameterizedTest
@CsvSource("testUser")
void failLogin2(String username) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/login.html");
// 输入账号
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
userName.sendKeys(username);
sleep(6000);
// 点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
// 截图
getScreenShotAs(getClass().getName());
}
// 密码错误
@Order(4)
@ParameterizedTest
@CsvSource("testUser,1234567")
void failLogin3(String username,String password) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/login.html");
// 输入账号
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
userName.sendKeys(username);
// 输入密码
WebElement pwd=webDriver.findElement(By.cssSelector("#password"));
pwd.sendKeys(password);
sleep(6000);
// 点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
// 截图
getScreenShotAs(getClass().getName());
}
// 正确输入
@Order(5)
@ParameterizedTest
@CsvFileSource(resources = "LoginSucess.csv")
void successLogin(String username,String password,String url) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/login.html");
// 输入账号
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
userName.sendKeys(username);
// 输入密码
WebElement pwd=webDriver.findElement(By.cssSelector("#password"));
pwd.sendKeys(password);
sleep(6000);
// 点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
// 跳转到列表页
// 获取到当前页面url
String cur_url=webDriver.getCurrentUrl();
// 如果url=http://localhost:8081/myblog_list.html 测试通过,否则测试不通过
Assertions.assertEquals(url,cur_url);
// 截图
getScreenShotAs(getClass().getName());
}
}
3.4 测试个人博客的我的博客列表页
创建 MyBlogListTest 类
1. 测试我的博客列表页是否正常显示
代码展示
// 设置优先级
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MyBlogListTest extends AutoTestUtils {
// 正确输入
@Order(1)
@ParameterizedTest
@CsvSource("wx,123456")
void successLogin(String username,String password) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/login.html");
// 输入账号
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
userName.sendKeys(username);
// 输入密码
WebElement pwd=webDriver.findElement(By.cssSelector("#password"));
pwd.sendKeys(password);
sleep(6000);
// 点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
}
// 我的博客列表页正常显示
@Order(2)
@Test
void MyBlogListPage(){
// 检查查看全文按钮
webDriver.findElement(By.cssSelector("#artlist > div:nth-child(1) > a:nth-child(4)"));
// 检查修改按钮
webDriver.findElement(By.xpath("//*[@id=\"artlist\"]/div[1]/a[2]"));
// 检查删除按钮
webDriver.findElement(By.cssSelector("#artlist > div:nth-child(1) > a:nth-child(6)"));
}
}
3.5 测试主页的博客列表页
创建BlogListTest
1. 主页的博客列表页是否正常显示
代码显示
// 设置优先级
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogListTest extends AutoTestUtils{
// 正确输入
@Order(1)
@ParameterizedTest
@CsvSource("wx,123456")
void successLogin(String username,String password) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/login.html");
// 输入账号
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
userName.sendKeys(username);
// 输入密码
WebElement pwd=webDriver.findElement(By.cssSelector("#password"));
pwd.sendKeys(password);
sleep(6000);
// 点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
}
// 博客列表页正常显示
@Order(2)
@Test
void MyBlogListPage(){
webDriver.get("http://localhost:8081/blog_list.html");
// 检查查看全文按钮
webDriver.findElement(By.xpath("//*[@id=\"artlist_div\"]/div[1]/a"));
}
}
3.6 测试博客编辑页
创建BlogEditTest类
1. 博客编辑页是否可以正常打开
2. 测试填写博客标题和正文,博客是否可以正常发布
代码实现
// 设置优先级
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogEditTest extends AutoTestUtils {
// 正确输入
@Order(1)
@ParameterizedTest
@CsvSource("wx,123456")
void successLogin(String username,String password) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/login.html");
// 输入账号
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
userName.sendKeys(username);
// 输入密码
WebElement pwd=webDriver.findElement(By.cssSelector("#password"));
pwd.sendKeys(password);
sleep(6000);
// 点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
}
// 测试编辑博客,标题输入是否正常、正文输入是否正常、发布按钮是否正常、博客列表第一个博客是否是“自动化测试”
@Order(2)
@Test
void EditBlog() throws InterruptedException, IOException {
// 找到写博客按钮,点击
webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 通过JS输入标题
((JavascriptExecutor)webDriver).executeScript("document.getElementById(\"title\").value=\"自动化测试\"");
sleep(3000);
// 点击发布
webDriver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button")).click();
sleep(2000);
// 点击弹窗取消
webDriver.switchTo().alert().dismiss();
sleep(3000);
// 获取当前页面的url
String cur_url=webDriver.getCurrentUrl();
Assertions.assertEquals("http://localhost:8081/myblog_list.html", cur_url);
// 获取第一篇博客标题
String first_blog_title=webDriver.findElement(By.cssSelector("#artlist > div:nth-child(1) > div.title")).getText();
// 获取第一篇博客发布时间
String first_blog_time=webDriver.findElement(By.xpath("//*[@id=\"artlist\"]/div[1]/div[2]")).getText();
// 校验博客标题是不是自动化测试
Assertions.assertEquals("自动化测试",first_blog_title);
// 如果时间是2023年-10月-15发布的,测试通过
if(first_blog_time.contains("2023-10-15")){
System.out.println("测试通过");
}else{
System.out.println("当前时间是:"+first_blog_time);
System.out.println("测试不通过");
}
getScreenShotAs(getClass().getName());
}
}
3.7 测试博客详情页
创建BlogDetailTest类
1. 测试博客详情页是否符合预期
代码实现
// 设置优先级
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogDetailTest extends AutoTestUtils {
// 正确输入
@Order(1)
@ParameterizedTest
@CsvSource("wx,123456")
void successLogin(String username,String password) throws InterruptedException, IOException {
webDriver.get("http://localhost:8081/login.html");
// 输入账号
WebElement userName=webDriver.findElement(By.cssSelector("#username"));
userName.sendKeys(username);
// 输入密码
WebElement pwd=webDriver.findElement(By.cssSelector("#password"));
pwd.sendKeys(password);
sleep(6000);
// 点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
}
// 博客详情页正常显示
// 测试评论文本输入框、测试评论按钮
@Order(2)
@Test
void MyBlogListPage() throws InterruptedException {
webDriver.get("http://localhost:8081/blog_list.html");
sleep(1000);
// 检查查看全文按钮
webDriver.findElement(By.xpath("//*[@id=\"artlist_div\"]/div[1]/a")).click();
// 评论文本输入框
webDriver.findElement(By.cssSelector("#comment_content"));
// 评论按钮
webDriver.findElement(By.cssSelector("#addcomment > input"));
}
}
3.8 测试套件
创建RunSuite类,用来指定哪些测试类需要运行,以及指定执行顺序。
@Suite
// 类的书写顺序就是执行顺序
@SelectClasses({registTest.class, loginTest.class, MyBlogListTest.class,BlogListTest.class,
BlogEditTest.class,BlogDetailTest.class})
public class RunSuite {
}
4. 该自动化测试使用到的技术以及亮点
本次测试,我是先根据自己的项目以脑图的方式设计了一个UI自动化测试用例,然后根据这个测试用例使用了selenium自动化测试工具和JUnit5单元测试框架结合实现的。
亮点:
使用了JUnit5中提供的注解:JUnit5的注解能够帮助开发人员更方便地编写和管理测试用例,如@BeforeAll、@BeforeEach、@Test等。
只创建一次驱动对象:通过只创建一次驱动对象,避免了每个测试用例都创建和销毁驱动对象的时间耗费,提高了测试用例执行的效率。
使用参数化:通过使用参数化,可以在一个测试方法中多次执行不同的测试数据,提高了测试覆盖率,同时减少了编写重复的测试用例的工作量。
使用测试套件:测试套件可以将多个测试类组合在一起执行,方便同时执行多个相关的测试用例,提高了测试效率和整体的测试覆盖率。
使用了等待:在自动化测试中,等待是非常重要的一环,可以通过添加等待逻辑来确保测试用例在某些特定的场景下等待某个元素的出现或消失,从而提高测试稳定性和可靠性。
使用了屏幕截图:当测试用例执行失败时,通过自动截取屏幕截图可以更直观地展示失败的原因和具体的情况,方便开发人员进行问题的定位和调试。同时,屏幕截图也可以作为测试报告的一部分,更直观地展示测试结果。