针对博客系统进行web自动化测试
文章目录
- 针对博客系统进行web自动化测试
- 引入依赖
- 创建出合适的目录结构
- AutoTestUtils
- BlogLoginTest
- BlogListTest
- BLogEditTest
- BlogDetailTest
- 使用套件执行
 
 
关于博客系统的自动化测试的源代码已经上传至gitee
链接
引入依赖
首先在pom.xml上导入依赖
注意: 在导入依赖的时候要记得刷新一下maven,确保依赖真的下载下来了
<dependencies>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>4.0.0</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.8.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-suite</artifactId>
        <version>1.8.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>
创建出合适的目录结构
创建出文件的目录结构,在Test包下面放测试的方法,在common包下面放一些通用的方法
这样子项目结构就会很清晰明了

AutoTestUtils
在每个测试类中可能都要创建驱动对象,频繁的创建和销毁对象,要是测试类很多的话,就很消耗资源,增加运行时间,所以最好单独创建一个方法,用来创建对象,这样子就不用频繁创建驱动对象了
由于这一块是所有的测试类都要调用的,所以单独封装出一个类,作为公用的类AutoTestUtils
//创建出驱动对象
 public static ChromeDriver createDriver() {
     //要是还没有创建出对象,就创建出一个浏览器/驱动对象
     if (chromeDriver == null) {
         chromeDriver = new ChromeDriver();
         //要是代码执行得很快,就会导致前端没渲染好,找不到元素的问题,所以要使用等待机制
         //隐式等待---最多等待10s
         chromeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
     }
     return chromeDriver;
 }
在实际的测试过程中,使用的是无头模式,根本就不会看到浏览器的页面,要是报错的话,就需要将报错的页面保存一下,方便排查问题
所以要用到屏幕截图
保存屏幕截图的时候,截图最好按照年月日 时分秒 毫秒的方式来保存,方便后面报错的时候定位错误
//设置屏幕截图的文件类型和目录类型
public List<String> getTime() {
    //使用SimpleDataFormat来进行时间转换
    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> lists = new ArrayList<>();
    lists.add(dirName);
    lists.add(fileName);
    return lists;
}
/*
获取屏幕截图,将所有的测试用例的结果都保存下来,便于后面报错发现问题
str表示是哪个类调用了屏幕截图
 */
public void getScreenShot(String str) throws IOException {
    List<String> list = getTime();
    //希望屏幕截图保存的名称: 目录名 + 文件名(年月日 时分秒 毫秒)
    //"./src/test/java/BlogAutoTest/"
    String fileName = "./src/test/java/BlogAutoTest/" + list.get(0)+"/" + str +"_" + list.get(1)+ ".png";
    File srcFile = chromeDriver.getScreenshotAs(OutputType.FILE);
    //将屏幕截图生成的文件放到指定的文件路径下面
    FileUtils.copyFile(srcFile,new File(fileName));
}
BlogLoginTest
检查登录页面的情况的时候,主要是检查 页面能不能正常显示 页面登录成功的情况 页面登录失败的情况
package BlogAutoTest.Tests;
import BlogAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import java.io.IOException;
//指定测试用例的执行顺序
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)//手动指定测试用例的执行顺序[注解]
public class BlogLoginTest extends AutoTestUtils {
    //在测试登录页的时候,会有两个必做的步骤
    //1.创建出驱动对象   2.访问url
    //这个方法一定是是在其他的用例执行之前,就要先执行一次的,所以使用的是@BeforeAll,所以要使用static来修饰
    public static  ChromeDriver chromeDriver = createDriver();//创建驱动对象放到方法外面去,后面还要使用
    @BeforeAll
    public static  void BaseControl() {
        chromeDriver.get("http://47.96.166.241:8080/blog_system/login.html");
    }
    /*
    检查页面是否能正常打开
    检查点: 主页  写博客  头像
     */
    @Test
    @Order(1)
    public void  loginPageLoadSuc() throws IOException {
        chromeDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)"));
        chromeDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
        chromeDriver.findElement(By.cssSelector("body > div.nav > img"));
        //屏幕截图,并且将类名传回去
        getScreenShot(getClass().getName());
    }
    /*
    检查页面的登陆成功的情况
     */
    //测试的不止一个账号,所以要使用参数化来进行多账号验证
    @ParameterizedTest
    @CsvSource({"zhangsan,123","lisi,123"})
    public void LoginSuc(String name, String password) throws IOException {
        //当登录别的账号的时候,就要先将之前的账号密码框清空,再进行登录
        chromeDriver.findElement(By.cssSelector("#username")).clear();
        chromeDriver.findElement(By.cssSelector("#password")).clear();
        chromeDriver.findElement(By.cssSelector("#username")).sendKeys(name);
        chromeDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        chromeDriver.findElement(By.cssSelector("body > div.login-container > form > div > div:nth-child(4) > input")).click();
        //上面的三步只是登录的基本步骤,并不能保证能登录成功,所以还要对跳转之后的页面进行检查,要是找不到元素的话就会报错
        //要是能登录成功,就一定能找到"查看全文的按钮"和"登录账号名称"
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > h3"));
        getScreenShot(getClass().getName());//屏幕截图,注意是:添加在返回之前,因为这里是测试了两个账号,所以会有两张截图
        //当一个账号登录成功的时候,想再登录另一个账号的时候,此时就找不到上面的3个元素了,因为此时页面已经不再是登录页面了,
        //所以要退回到登录的页面
        chromeDriver.navigate().back();
    }
    /*
    检查页面登录失败的情况
    需要注意的是:此时我们验证的是登录失败的情况,所以我们给定错误的账号或者密码,来看看错误的界面是否符合预期,要是符合预期的话,测试用例跑完之后不会报错
     */
    @ParameterizedTest
    @CsvSource({"zhangsan1,123","lisi1,123"})//测试的是登录错误的情况,所以就要使用错误的账号/密码
    @Order(2)
    public void LoginFail(String name, String password) throws IOException {
        chromeDriver.findElement(By.cssSelector("#username")).clear();
        chromeDriver.findElement(By.cssSelector("#password")).clear();
        chromeDriver.findElement(By.cssSelector("#username")).sendKeys(name);
        chromeDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        chromeDriver.findElement(By.cssSelector("body > div.login-container > form > div > div:nth-child(4) > input")).click();
        //检查登录页面跳转失败的情况,结果发现,在登录成功的页面中也有这个元素,所以仅仅只有这个元素是不能判断的,可以获取一下文本
        String expectation = "用户名或者密码错误,登录失败!";
        String actual = chromeDriver.findElement(By.cssSelector("body")).getText();
        Assertions.assertEquals(expectation, actual);
        getScreenShot(getClass().getName());//屏幕截图,注意是:添加在返回之前,因为这里是测试了两个账号,所以会有两张截图
        chromeDriver.navigate().back();
    }
    //在执行完所有的测试方法之后都要将驱动对象销毁掉,所以使用的是@AfterAll,方法要由static来修饰
    //但是由于使用的是套件,所以要在最后一个测试类中销毁驱动对象,所以不能写在这里
}
BlogListTest
测试博客列表页,主要测试的就是页面是否能正常打开
package BlogAutoTest.Tests;
import BlogAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.AfterAll;
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 BlogListTest extends AutoTestUtils {
    public static ChromeDriver chromeDriver = createDriver();
    @BeforeAll
    public static  void BaseControl() {
        chromeDriver.get("http://47.96.166.241:8080/blog_system/blog_list.html");
    }
    /*
    测试列表页是否能展示出来
    检查点: 头像 查看全文按钮  文章
     */
    @Test
    public void listPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > img"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > div:nth-child(4) > span:nth-child(1)"));
    }
}
BLogEditTest
对于测试博客编辑页,测试的有: 页面能不能正常显示出来 能不能写出并提交博客
package BlogAutoTest.Tests;
import BlogAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogEditTest extends AutoTestUtils {
    public static ChromeDriver chromeDriver = createDriver();
    @BeforeAll
    public static void BaseControl() {
        chromeDriver.get("http://47.96.166.241:8080/blog_system/blog_edit.html");
    }
    /*
    检查博客编辑页有没有展示出来
    检查点:发布文章 文章标题
     */
    @Order(1)
    @Test
    public void editPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("#submit"));
        chromeDriver.findElement(By.cssSelector("#blog-title"));
    }
    /*
    检查博客编辑页能不能写文章并提交
     */
    @Order(2)
    @Test
    public void editSubmitBlog() {
        String expectation = "测试发布";//博客的标题
        chromeDriver.findElement(By.cssSelector("#blog-title")).sendKeys(expectation);
        //因为博客系统使用的第三方(editor.md),所以不能直接获取到输入框元素,但是可以获取到一些格式
        chromeDriver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(21) > a > i")).click();
        chromeDriver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(5) > a > i")).click();
        chromeDriver.findElement(By.cssSelector("#submit")).click();//点击提交
        String actual = chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.title")).getText();
        //看看实际发布的博客信息与期望的博客标题是否一样
        Assertions.assertEquals(expectation, actual);
    }
    
}
BlogDetailTest
package BlogAutoTest.Tests;
import BlogAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.AfterAll;
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 BlogDetailTest extends AutoTestUtils {
    public static ChromeDriver chromeDriver = createDriver();
    @BeforeAll
    public static void baseControl() {
        chromeDriver.get("http://47.96.166.241:8080/blog_system/blog_detail.html?blogId=10");
    }
    /*
    测试博客详情页是否正确
    检查点:时间  账号  标题
     */
    @Test
    public void detailPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div > div.blog-date"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > h3"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div > h3"));
    }
    //在套件中,当同时执行了多个类,销毁一定是最后一个步骤,所以要到处搬来搬去,永远保证最后一个执行
    @AfterAll
    public static void quit() {
        chromeDriver.quit();
    }
}
使用套件执行
想要运行以上的几个测试类,可以使用套件来指定统一运行
使用套件(suite)就能很好的管理各个测试用例的执行
package BlogAutoTest.Tests;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;
//使用套件来统一执行测试用例(可以手动指定类名,也可以手动指定包名,但是只会执行包中以Test或者Tests结尾的测试类)
@Suite
@SelectClasses({BlogLoginTest.class,BlogListTest.class,BlogEditTest.class,BlogDetailTest.class})
public class runSuite {
}
关于执行web自动化测试, 需要对实际场景的分析和理解,要理清楚程序的执行步骤和执行预期结果,一旦出现问题,要学会排查错误,看看到底是自己的自动化代码写错了导致误报,还是系统本身的错误







![[oeasy]python0104_指示灯_显示_LED_辉光管_霓虹灯](https://img-blog.csdnimg.cn/img_convert/04725067ef86f6c13e361d1c583a2d72.png)












