针对博客系统的自动化测试

针对博客系统进行web自动化测试


关于博客系统的自动化测试的源代码已经上传至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  chromeDriver;
   //创建出驱动对象
    public static ChromeDriver createDriver() {
        //要是还没有创建出对象,就创建出一个浏览器/驱动对象
        if (chromeDriver == null) {
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--remote-allow-origins=*");
            chromeDriver = new ChromeDriver(options);
            //要是代码执行得很快,就会导致前端没渲染好,找不到元素的问题,所以要使用等待机制
            //最多等待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:8081/myblog_list.html");
    }

    /*
    测试列表页是否能展示出来
    检查点: 头像 查看全文按钮  文章
     */
    @Test
    public void listPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > img"));
        chromeDriver.findElement(By.cssSelector("#artDiv > div:nth-child(1) > a:nth-child(4)"));
    }

}

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:8081/blog_add.html");
    }
    /*
    检查博客编辑页有没有展示出来
    检查点:发布文章 文章标题
     */
    @Order(1)
    @Test
    public void editPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("body > div.blog-edit-container > div.title > button"));
        chromeDriver.findElement(By.cssSelector("#title"));
    }

    /*
    检查博客编辑页能不能写文章并提交
     */
    @Order(2)
    @Test
    public void editSubmitBlog() {
        String expectation = "测试发布";//博客的标题
        chromeDriver.findElement(By.cssSelector("#title")).sendKeys(expectation);
        //因为博客系统使用的第三方(editor.md),所以不能直接获取到输入框元素,但是可以获取到一些格式
        chromeDriver.findElement(By.cssSelector("#editorDiv > div.CodeMirror.cm-s-default.CodeMirror-wrap > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div")).click();
        chromeDriver.findElement(By.cssSelector("#editorDiv > div.editormd-toolbar > div > ul > li:nth-child(7) > a > i")).click();
    }
    //在套件中,当同时执行了多个类,销毁一定是最后一个步骤,所以要到处搬来搬去,永远保证最后一个执行
}

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:8081/blog_content.html?id=6");
    }
    /*
    测试博客详情页是否正确
    检查点:时间  账号  标题
     */
    @Test
    public void detailPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("#updatetime"));
        chromeDriver.findElement(By.cssSelector("#username"));
        chromeDriver.findElement(By.cssSelector("#title"));
    }

}

BlogHomepageTest

package BlogAutoTest.Tests;

import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;

import static BlogAutoTest.common.AutoTestUtils.createDriver;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class) //测试方法执行顺序
public class BlogHomepageTest {
    public static ChromeDriver chromeDriver = createDriver();
    @BeforeAll
    public static void baseControl() {
        chromeDriver.get("http://47.96.166.241:8081/blog_list.html");
    }
    @Test
    public void homepageLoadSuc(){
        chromeDriver.findElement(By.cssSelector("#artListDiv > div:nth-child(1) > div.date"));
        chromeDriver.findElement(By.cssSelector(("#artDiv > div.blog-pagnation-wrapper > button:nth-child(1)")));
        chromeDriver.findElement(By.cssSelector("#artDiv > div.blog-pagnation-wrapper > button:nth-child(4)"));
    }
    @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,BlogHomepageTest.class})
public class  runSuite {

}

关于web自动化测试的代码其实都是比较固定的,但是需要对实际场景的分析和理解,要理清楚程序的执行步骤和执行预期结果,一旦出现问题,要学会排查错误,看看到底是自己的自动化代码写错了导致误报,还是系统本身的错误

image-20230421205254075

最终自动化测试的结果(9个测试用例都跑通了)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值