一)项目简介:
用户管理系统是依据于前后端分离来实现的,是基于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标签内的文本的值的;
二)针对于列表页+新增用户进行测试:
校验添加完成元素成功以后是否成功跳转到了首页,校验一些重要信息是否正确
@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); } }
三)针对于列表页和删除用户进行测试:
删除单个用户
删除多个用户
四)针对于列表页和批量查询用户做测试:
五)针对于列表页和修改用户做测试: