JAVA项目测试----用户管理系统

一)项目简介:

用户管理系统是依据于前后端分离来实现的,是基于Spring SpringBoot Spring MVC,SpringAOP,MyBatis等框架来实现的一个用户管理网站,并且已经部署到了云服务器上,

目前的用户管理系统实现了超级管理员的注册功能,用户管理员的新增,删除,修改,用户分页展示,批量删除,多条件查询等功能

二)测试计划:

测试对象:基于SSM实现的用户管理系统

测试目的:验证用户管理系统是否可以正常的运行,验证用户管理系统是否符合用户的需求

测试点:主要针对常用的主流程功能进行测试,除此之外还有界面测试+功能测试+兼容性测试+安全性测试+可靠性测试+容错性测试+性能测试+网络测试;

测试方法:主要使用黑盒测试方法,自动化测试工具使用Selenium4+junit5

三)手工测试用例的编写:

 飞书访问链接:https://nxqjlyz94q2.feishu.cn/wiki/GwIRwI5Ebi3qtDkfJq4cG3bPnWe?create_from=create_doc_to_wiki#mindmap

一)针对于登录界面进行测试:

一)界面测试:


二)功能测试:

三)兼容性+易用性+安全性测试+性能测试:

4)可靠性:让软件运行几周,软件正常运行的时间/软件在这段期间运行的时间+软件在这段期间出故障的时间

二)针对于用户列表页进行功能测试:(其他非功能测试和上出的登录非功能测试类似)

三)针对于用户修改页面和用户修改页面进行功能测试(其他非功能测试和上出的登录非功能测试类似)

四)基于selenium4+junit5进行自动化测试

创建全局驱动对象,避免频繁创建销毁

一)针对于登录界面进行自动化测试

1)校验首页是否正常展示功能并且通过多参数验证用户登录功能


@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LoginTest  {
    private static ChromeDriver driver= (ChromeDriver) CommonDriver.getDriver();
    //验证首页元素展示是正确
    @BeforeEach
    public void getUrl(){
        //打开浏览器
        driver.get("http://127.0.0.1:8080/login.html");
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
    }
    @Order(1)
    @Test
    void CheckElementLogin(){
        //1.检查页面上一些文字的显示,url是否正确
        String text1=driver.findElement(By.cssSelector("#body > div > h3")).getText();
        String text2=driver.findElement(By.cssSelector("#body > div > div:nth-child(2) > label")).getText();
        String text3=driver.findElement(By.cssSelector("#body > div > div:nth-child(3) > label")).getText();
        String text4=driver.findElement(By.cssSelector("#submit")).getAttribute("value");
        String url=driver.getCurrentUrl();
        //2.校验信息元素是否正确,比如说校验文本是否符合预期
        Assertions.assertEquals(text1,"管理员登录");
        Assertions.assertEquals(text2,"用户名:");
        Assertions.assertEquals(text3,"密码:");
        Assertions.assertEquals(text4,"登录");
        Assertions.assertEquals(url,"http://127.0.0.1:8080/login.html");
    }
    @AfterEach
    public void close(){
        driver.close();
    }
}

2)针对于登录构建多数据登录

@ParameterizedTest
    @MethodSource("loginData")
    public void login(String username,String password) throws InterruptedException {
        //定位到登陆页面中的输入框核按钮进行登陆操作
        driver.findElement(By.cssSelector("#loginname")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(10);
    }
    public static Stream<Arguments> loginData(){
        return Stream.of(Arguments.arguments("张三","123"),Arguments.arguments("zhangsan","admin"));
    }
多组参数化执行本身不会新打开一个浏览器的窗口重新进行输入第二组参数化的执行还是使用的是第一组参数画的界面,比如说构造数据的时候会出现当时用到第一组参数化的构造的参数以后,此时还会针对于第二组参数来进行参数化的构造(此时和第一组参数使用的是同一个界面),如果说此是针对于第一组参数用户登陆成功了,直接跳转到列表页了,那么当第二组参数参数构造以后,系统执行以后发现此时页面是在列表页,自然无法定位到输入框和按钮,此时就会出现nosuchelement异常

@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LoginTest  {
    private static ChromeDriver driver=  CommonDriver.getDriver();
   // 验证首页元素展示是正确
    @BeforeAll
    public static void getUrl(){
        //打开浏览器
        driver.get("http://127.0.0.1:8080/login.html");
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
    }

    @Test
    @Order(2)
    void CheckElementLogin(){
        //1.检查页面上一些文字的显示,url是否正确
        String text1=driver.findElement(By.cssSelector("#body > div > h3")).getText();
        String text2=driver.findElement(By.cssSelector("#body > div > div:nth-child(2) > label")).getText();
        String text3=driver.findElement(By.cssSelector("#body > div > div:nth-child(3) > label")).getText();
        String text4=driver.findElement(By.cssSelector("#submit")).getAttribute("value");
        String url=driver.getCurrentUrl();
        //2.校验信息元素是否正确,比如说校验文本是否符合预期
        Assertions.assertEquals(text1,"管理员登录");
        Assertions.assertEquals(text2,"用户名:");
        Assertions.assertEquals(text3,"密码:");
        Assertions.assertEquals(text4,"登录");
        Assertions.assertEquals(url,"http://127.0.0.1:8080/login.html");
    }
   //
   @ParameterizedTest
   @Order(1)
   @MethodSource("loginData")
   public void login(String username,String password) throws InterruptedException {
        //这个参数化本身不会新打开一个浏览器的窗口重新进行输入
       //定位到登陆页面中的输入框核按钮进行登陆操作
       driver.findElement(By.cssSelector("#loginname")).sendKeys(username);
       driver.findElement(By.cssSelector("#password")).sendKeys(password);
       driver.findElement(By.cssSelector("#submit")).click();
       //第一组参数构造失败以后,登陆失败,手动使用Alert框来将输入框按钮按下
       Alert alert=driver.switchTo().alert();
       alert.accept();
       Thread.sleep(10);
   }
    public static Stream<Arguments> loginData(){
        return Stream.of(Arguments.arguments("zhangsan","admin"));
    }
    @AfterAll
    public static void close() throws InterruptedException {
        driver.close();
    }
}

1)通过上面进行参数化的校验以后,就可以构造成正确的用户名和错误密码来进行测试,还可以根据更多的测试点进行测试

2)一定要注意driver.getAttribute()是获取到对应的属性值,element的getText方法是用来获取html标签内的文本的值的;

二)针对于列表页+新增用户进行测试:

1)校验添加完成用户成功以后是否成功跳转到了首页,校验一些首页的重要信息比如说一些重要的文本,一些标签属性是否正确,一般来说出现异常的状况就是:跳转到最终的页面以后要么页面无法找到元素(服务器崩了),要么页面中的内容不符合最终的预期(前端出现问题)

2)此时添加了隐式等待以后,点击弹窗按钮以后弹出警告框并且切换到警告框并且出现no such alert报错,本身隐式等待的作用就是需要等待浏览器加载完成以后再来找到对应的元素,selenium本身不可以通过findElement方法来找到警告框对应的前端代码,隐式等待本身不会等待警告框展示和系统弹窗展示,所以会出现代码执行过快警告框仍然没有出现的情况

既然隐式等待在这里面不生效了,那么就使用强制等待,显示等待也不行,显示等待是等待对应的元素出现才查找,必须使用Thread.sleep(100)

3)关闭弹窗以后才可以正确的获取到当前页面的元素,也就是说可以通过获取当前页面元素可以来进行判断弹窗是否正确的关闭

@TestMethodOrder(MethodOrderer.class)
public class ListTest {
    public int count=0;
    private static ChromeDriver driver=CommonDriver.getDriver();
    //1.检测列表页中的元素信息,校验当前页面中的元素是否符合预期
    @Test
    @Order(1)
    public void TestList() throws InterruptedException {
        //1.前提是必须用户登录过了,不会打回给前端
        driver.get("http://127.0.0.1:8080/login.html");
        driver.findElement(By.cssSelector("#loginname")).sendKeys("zhangsan");
        driver.findElement(By.cssSelector("#password")).sendKeys("admin");
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(3000);
        //2.点击登录按钮
        Alert alert=driver.switchTo().alert();
        alert.accept();
        Thread.sleep(3000);
      //显示等待,防止程序执行速度远远高于代码执行速度而导致页面无法抓取元素
        //3.校验首页信息是否正确
        String text1=driver.findElement(By.xpath("/html/body/div/h3")).getText();
        Assertions.assertEquals(text1,"用户信息列表");
        String text2=driver.findElement(By.cssSelector("body > div > div:nth-child(2) > form > div:nth-child(2) > label")).getText();
        Assertions.assertEquals(text2,"籍贯");
        //4.跳转到新增用户界面,并验证新增界面的一些元素是否正确
        driver.findElement(By.cssSelector("body > div > div:nth-child(3) > a:nth-child(1)")).click();
        String text=driver.findElement(By.cssSelector("body > div > h3")).getText();
        Assertions.assertEquals(text,"添加用户");

    }
    //2.进入到新增用户的界面,进行添加信息以后跳转到首页
    @Order(2)
    @ParameterizedTest
    @MethodSource("")
    public void TestAddUser(User user) throws InterruptedException {
        //1.填写登陆名字,用户名密码和登陆密码
        driver.findElement(By.cssSelector("#loginname")).sendKeys(user.getLoginname());
        driver.findElement(By.cssSelector("#username")).sendKeys(user.getUsername());
        driver.findElement(By.cssSelector("#password")).sendKeys(user.getPassword());
        driver.findElement(By.cssSelector("#password2")).sendKeys(user.getPassword());
        //2.填写对应的按钮的操作
        if(user.getSex().equals("男")) driver.findElement(By.cssSelector("#man")).click();
        else driver.findElement(By.cssSelector("#women")).click();
        //3.下拉框
        Select select=new Select(driver.findElement(By.cssSelector("#address")));
        select.selectByVisibleText(user.getAddress());
        //4.qq邮箱
        driver.findElement(By.cssSelector("#qq")).sendKeys(user.getQq());
        driver.findElement(By.cssSelector("#email")).sendKeys(user.getEmail());
        driver.findElement(By.cssSelector("#age")).sendKeys(""+user.getAge());
        if(user.getIsadmin()==1) driver.findElement(By.cssSelector("#admin_yes")).click();
            else  driver.findElement(By.cssSelector("#admin_no")).click();
        //5.点击按钮
       driver.findElement(By.cssSelector("#btn_sub")).click();
       //6.是否继续添加
        Thread.sleep(4000);
        Alert alert=driver.switchTo().alert();
            alert.accept();
            alert.accept();
 //首先弹出对话框添加成功,然后弹出对话框是否手动添加,可以通过增加的动态参数的user个数来灵活地进行调配
    }
    public static Stream<User> TestAddUser() throws InterruptedException {
        User user1=new User();
        user1.setUsername("wangwu");
        user1.setPassword("wangwu");
        user1.setLoginname("wangwu");
        user1.setIsadmin(1);
        user1.setAddress("北京");
        user1.setEmail("wangwu");
        user1.setSex("男");
        user1.setAge(10);
        user1.setQq("123");
        Thread.sleep(3000);
        User user2=new User();
        user2.setUsername("lisi");
        user2.setPassword("lisi");
        user2.setLoginname("lisi");
        user2.setIsadmin(1);
        user2.setAddress("上海");
        user2.setEmail("lisi");
        user2.setSex("男");
        user2.setAge(10);
        user2.setQq("123");
        Thread.sleep(3000);
      return Stream.of(user1,user2);
    }
}

4)针对于测试的一些重要信息进行截图:

public class GetTimeClass {
    public static void getScreenShot( ChromeDriver driver,String className){
        List<String> times=getTime();
        String fatherPath="./src/test/autotest-"+className+"-"+times.get(0)+"/"+times.get(1)+".png";
        File sourceFile=driver.getScreenshotAs(OutputType.FILE);
        FileUtil.copyFile(sourceFile,new File(fatherPath));
    }
    public static List<String> getTime(){
        //文件名格式20220101-214130-毫秒
        SimpleDateFormat format1=new SimpleDateFormat("yyyyMMdd-HHmmssSS");
        //文件夹名称格式2022-08-01
        SimpleDateFormat format2=new SimpleDateFormat("yyyy-MM-dd");
        String fileName=format1.format(System.currentTimeMillis());
        String dirName=format2.format(System.currentTimeMillis());
        List<String> result=new ArrayList<>();
        result.add(dirName);
        result.add(fileName);
        return result;
    }
}
三)针对于列表页和删除用户进行测试:

删除单个用户

删除多个用户

四)针对于列表页和批量查询用户做测试:

总结:使用selenium4+junit5作为自动化测试针对想试试自动化测试的亮点以及总结:

1)@Suite(),@SelectClasses("createDriver","业务类","destoryDriver"),如果选择@SelectClasses来指定运行的类的时候,那么类的执行顺序是按照我们在@SelectClasses中手动指定类的执行顺序来执行的

2)不是说每一个用例都需要添加屏幕截图操作,需要考察用例本身的复杂程度和问题定位的难度,以及用例的核心程度来进行考察

1)使用注解@Test,@BeforeEach,@BeforeAll,@AfterEach,@AfterAll

1.1)加上这些注解以后就不需要使用创建Main函数作为方法执行的入口了,就不需要通过传统的创建大量对象的方式来调用测试方法了,避免生成大量对象造成空间浪费以及很好的提升了性能;

1.2)测试模块和测试模块之间就可以解耦合,一个测试用例执行失败,不会影响其他用例的执行,防止大量测试用例执行失败而造成测试用例浪费,模块之间也做到了很好的解耦合;

2)通过static修饰静态变量,全局只是创建一次驱动对象,避免重复创建驱动对象造成时间和空间的浪费,防止每一个用例都重新创建Driver和销毁Driver对象

3)支持单参数,多参数,方法参数,动态参数来减少用例的冗余,保证用例的简介,保证可读性

4)通过junit中的测试套件,一次执行所有我们想要运行的自动化测试用例

5)使用隐式等待和强制等待(Alert框,警告框无法定位,可能代码执行速度远远大于警告框弹出的速度,但是隐式等待和显示等待不会等待ALert框弹出以后程序在执行运行),一方面显示等待使用比较麻烦,另一方面隐式等待和显示等待混用会导致程序失效,提升自动化执行的稳定性,降低自动化误报的概率;

6)使用屏幕截图:方便问题的追溯和自动化执行问题的解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值