学生信息管理系统自动化测试
项目地址:
http://82.156.151.156:8080/login.html
一、系统测试用例
二、测试实现过程
先是根据自己的项目设计了一个 UI 自动化测试用例, 然后根据这个测试用例使用了 selenium4自动化测试工具和 JUnit5单元测试框架结合实现的 web 自动化测试.。
测试模块划分为三个,有三个包, 一个包下的类是工具类, 主要是用来创建驱动对象的, 避免在自动化测试的时候, 每次都要创建驱动对象. 另一个 包是放测试用例的, 一个页面一个测试类, 最后一个包是个测试套件,通过测试套件把测试类全部都加进去。
三、测试亮点
(1) 使用了 JUnit中提供的注解, 避免生成过多的对象, 造成资源和时间的浪费, 提高了自动化的执行效率;
(2)只创建了一次驱动对象, 避免每个用例重复创建驱动对象造成时间和资源的浪费;
(3)用例使用了参数化注解,保持用例的简洁, 提高代码的可读性;
(4)使用了测试套件, 降低了测试人员的工作量, 通过套件既可以指定哪些测试类需要运行, 也可以一次执行所有要运行的测试用例;
(5) 使用了屏幕截图, 方便问题的追溯以及问题的解决;
(6) 使用了等待, 如当页面发生跳转的时候, 或者页面还没来得及渲染的时候, 获取页面元素, 就会出现元素找不到的异常, 而这可能不是一个 bug, 所以需要加上隐式等待,提高了自动化的稳定性。
四、测试前准备工作
1.写好测试用例;
2.准备好测试数据;
3.创建测试环境:
(1)1. 创建一个 Maven 项目;
(2)导入自动化测试需要的相关依赖;
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version> <!-- 替换为你需要的版本号 --><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java --><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>3.4.0</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>25.0-jre</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</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>
(3)创建包,管理自己后续要写的代码。
四、写自动化测试代码
1.工具类
(1)创建驱动对象, 提供给其他页面使用;
(2)创建隐式等待, 作用于软件测试的整个生命周期;
(3)创建截图保存的路径;
(4)提供屏幕截图的方法, 以及保存截图的格式。
public class AutoTestUtils {public static EdgeDriver driver;// 创建驱动对象public static EdgeDriver getDriver() {System.setProperty("webdriver.edge.driver", "msedgedriver.exe");if(driver == null) {driver = new EdgeDriver();}// 创建隐式等待,作用于driver的整个生命周期 (10秒)//Duration.ofSeconds(10) 创建了一个持续时间对象,表示等待时间为10秒。然后,通过调用 toMillis() 方法,将持续时间转换为毫秒数。// 最后,使用 TimeUnit.MILLISECONDS 将毫秒作为单位传递给 implicitlyWait() 方法。driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10).toMillis(), TimeUnit.MILLISECONDS);return driver;}// 屏幕截图, 保存文件的格式//获取当前时间,并将其格式化为指定的文件名和文件夹名public List<String> getTime() {// 文件夹按照天数的维度进行保存// 文件格式 2023-4-3 20:07SimpleDateFormat 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 {// 调用 getTime() 方法获取当前日期和时间的列表List<String> list = getTime();// 构建截图文件的路径String filePath = "./src/test/java/com/example/student_manage_test/"+list.get(0)+"/"+str+"_"+list.get(1)+".png";// 获取页面截图并保存为文件//OutputType.FILE 是一个枚举类型,表示捕获页面截图的输出类型为文件。File srcFile = driver.getScreenshotAs(OutputType.FILE);//从源文件复制到指定路径下FileUtils.copyFile(srcFile, new File(filePath));}}
(5)释放驱动
@SpringBootTest
public class DriverQuitTest extends AutoTestUtils {public static EdgeDriver driver;//停止 WebDriver 的操作并释放相关资源@Testpublic void driverQuit() {driver = getDriver();driver.quit();}
}
2.测试登录界面
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LoginTest extends AutoTestUtils {public static EdgeDriver driver;@BeforeAllpublic static void baseController() {driver = getDriver();driver.get("http://82.156.151.156:8080/login.html");}/*** 检查登录页面是否正常打开* 检查登录页的登录,用户名,密码等字样是否出现*/@Test@Order(1)//标记方法在测试执行时的顺序public void loginPageLoadRight() throws IOException {// 查找登录页面标题元素的 CSS 选择器driver.findElement(By.id("loginname"));// 查找登录页面的第一个提示信息元素的 XPathdriver.findElement(By.id("password"));// 查找登录页面的第二个提示信息元素的 XPathdriver.findElement(By.cssSelector("#submit"));// 对当前页面进行截图getScreenShotAs(getClass().getName());}/*** 检查异常登录的情况 4 种情况* (1)账号密码错误* 账号密码错误, 会弹窗提示*/@ParameterizedTest@CsvSource({"admin,345", "zhangsan,111", "lucy,111"})@Order(2)public void loginFail(String loginname, String password) throws InterruptedException, IOException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 登录步骤driver.findElement(By.id("loginname")).sendKeys(loginname);driver.findElement(By.id("password")).sendKeys(password);driver.findElement(By.cssSelector("#submit")).click();// 检测登录失败的场景// 切换到弹窗, 进行弹窗的处理(隐式等待不生效,不得不加入强制等待)//等待时间WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("用户名或密码错误,请重试!"));driver.switchTo().alert().accept();//截图getScreenShotAs(getClass().getName());}/*** (2)未输入密码** @param loginname 登录名* @throws InterruptedException*/@ParameterizedTest@ValueSource(strings = {"张三"})@Order(3)public void loginFail2(String loginname) throws InterruptedException, IOException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 登录步骤driver.findElement(By.id("loginname")).sendKeys(loginname);driver.findElement(By.cssSelector("#submit")).click();// 检测登录失败的场景// 切换到弹窗, 进行弹窗的处理Thread.sleep(100);Alert alert = driver.switchTo().alert();// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("请先输入密码!"));alert.accept();getScreenShotAs(getClass().getName());}/*** 未输入用户名** @param password 密码* @throws InterruptedException*/@ParameterizedTest@ValueSource(strings = {"111"})@Order(4)public void loginFail3(String password) throws InterruptedException, IOException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 登录步骤driver.findElement(By.id("password")).sendKeys(password);driver.findElement(By.cssSelector("#submit")).click();// 检测登录失败的场景// 切换到弹窗, 进行弹窗的处理Thread.sleep(100);Alert alert = driver.switchTo().alert();// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("请先输入用户名!"));alert.accept();getScreenShotAs(getClass().getName());}/*** 账号,, 密码都没有输入** @throws InterruptedException*/@Test@Order(5)public void loginFail4() throws InterruptedException, IOException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();driver.findElement(By.cssSelector("#submit")).click();// 检测登录失败的场景// 切换到弹窗, 进行弹窗的处理Thread.sleep(100);Alert alert = driver.switchTo().alert();// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("请先输入用户名!"));// 警告弹窗alert.accept();getScreenShotAs(getClass().getName());}/*** 检查正常登录的情况* 页面是否显示登录名, 密码, 提交字样*///@ParameterizedTest指示一个测试方法是参数化测试方法,CsvSource指定参数化测试方法的参数来源为 CSV 格式的数据源。@ParameterizedTest@CsvSource({"admin,admin"})@Order(6)public void loginSuccess(String logianname, String password) throws IOException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 登录步骤driver.findElement(By.id("loginname")).sendKeys(logianname);driver.findElement(By.id("password")).sendKeys(password);driver.findElement(By.cssSelector("#submit")).click();//等待时间WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("登录成功"));driver.switchTo().alert().accept();getScreenShotAs(getClass().getName());// 一个用户测试完了,需要进行回退driver.navigate().back();}
}
3.测试学生列表界面
@SpringBootTest
public class ListTest extends AutoTestUtils {public static EdgeDriver driver;@BeforeAllpublic static void baseController() {driver = getDriver();driver.get("http://82.156.151.156:8080/login.html");}/*** 登录后学生列表列表页可以正常显示*/@Testpublic void MyListPageLoadRight() throws IOException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 先登录driver.findElement(By.id("loginname")).sendKeys("admin");driver.findElement(By.id("password")).sendKeys("admin");driver.findElement(By.cssSelector("#submit")).click();// 接收弹窗WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());driver.switchTo().alert().accept();// 使用适当的定位器(By)查询目标元素List<WebElement> elements = driver.findElements(By.xpath("//*[@id=\"info\"]/tr[1]"));// 验证查询结果是否为空assertTrue(elements.size() > 0);getScreenShotAs(getClass().getName());driver.navigate().back();}}
4.测试查询功能
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SelectTest extends AutoTestUtils {@BeforeAllpublic static void baseController() {driver = getDriver();driver.get("http://82.156.151.156:8080/login.html");}/*** 查询学生通过姓名*/@Test@Order(1)public void selectByStuname() throws IOException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 先登录driver.findElement(By.id("loginname")).sendKeys("admin");driver.findElement(By.id("password")).sendKeys("admin");driver.findElement(By.cssSelector("#submit")).click();// 接收弹窗WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());driver.switchTo().alert().accept();//传入参数driver.findElement(By.id("ipt_name")).sendKeys("超级管理员");driver.findElement(By.id("submit1")).click();// 使用适当的定位器(By)查询目标元素List<WebElement> elements = driver.findElements(By.xpath("//*[@id=\"info\"]/tr/th[3]"));// 验证查询结果是否为空assertTrue(elements.size() > 0);//截图getScreenShotAs(getClass().getName());}/*** 查询学生通过籍贯*/@Test@Order(2)public void selectByAddress() throws IOException {driver.findElement(By.id("ipt_name")).clear();driver.findElement(By.id("ipt_address")).clear();driver.findElement(By.id("ipt_stunum")).clear();//传入参数driver.findElement(By.id("ipt_address")).sendKeys("北京");driver.findElement(By.id("submit1")).click();// 使用适当的定位器(By)查询目标元素List<WebElement> elements = driver.findElements(By.xpath("//*[@id=\"info\"]/tr[1]/th[6]"));// 验证查询结果是否为空assertTrue(elements.size() > 0);//截图getScreenShotAs(getClass().getName());}/*** 查询学生通过学号*/@Test@Order(3)public void selectByStunum() throws IOException {driver.findElement(By.id("ipt_name")).clear();driver.findElement(By.id("ipt_address")).clear();driver.findElement(By.id("ipt_stunum")).clear();//传入参数driver.findElement(By.id("ipt_stunum")).sendKeys("2002");driver.findElement(By.id("submit1")).click();// 使用适当的定位器(By)查询目标元素List<WebElement> elements = driver.findElements(By.xpath("//*[@id=\"info\"]/tr/th[8]"));// 验证查询结果是否为空assertTrue(elements.size() > 0);//截图getScreenShotAs(getClass().getName());}/*** 查询学生通过姓名和籍贯*/@Test@Order(4)public void selectByStuname_Address() throws IOException {driver.findElement(By.id("ipt_name")).clear();driver.findElement(By.id("ipt_address")).clear();driver.findElement(By.id("ipt_stunum")).clear();//传入参数driver.findElement(By.id("ipt_name")).sendKeys("超级管理员");driver.findElement(By.id("ipt_address")).sendKeys("成都");driver.findElement(By.id("submit1")).click();// 使用适当的定位器(By)查询目标元素List<WebElement> elements = driver.findElements(By.xpath("//*[@id=\"info\"]/tr/th[3]"));// 验证查询结果是否为空assertTrue(elements.size() > 0);//截图getScreenShotAs(getClass().getName());}/*** 查询学生通过姓名、籍贯和学号*/@Test@Order(5)public void selectByStuname_Address_Stunum() throws IOException {driver.findElement(By.id("ipt_name")).clear();driver.findElement(By.id("ipt_address")).clear();driver.findElement(By.id("ipt_stunum")).clear();//传入参数driver.findElement(By.id("ipt_name")).sendKeys("超级管理员");driver.findElement(By.id("ipt_address")).sendKeys("成都");driver.findElement(By.id("ipt_stunum")).sendKeys("10000");driver.findElement(By.id("submit1")).click();// 使用适当的定位器(By)查询目标元素List<WebElement> elements = driver.findElements(By.xpath("//*[@id=\"info\"]/tr[1]/th[3]"));// 验证查询结果是否为空assertTrue(elements.size() > 0);//截图getScreenShotAs(getClass().getName());driver.navigate().back();}}
5.测试添加功能
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AddTest extends AutoTestUtils {@BeforeAllpublic static void baseSetup() {driver = getDriver();driver.get("http://82.156.151.156:8080/login.html");}/*** 添加用户成功测试* @throws IOException*/@Order(1)@ParameterizedTest@CsvSource({"李四,李四,111,111,20,1873234890819,2007"})public void addStudentSuccess(String loginname, String stuname, String password, String password2, int age,String phone,String stunum) throws IOException, InterruptedException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 先登录driver.findElement(By.id("loginname")).sendKeys("admin");driver.findElement(By.id("password")).sendKeys("admin");driver.findElement(By.cssSelector("#submit")).click();// 接收弹窗WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());driver.switchTo().alert().accept();// 点击添加用户按钮driver.findElement(By.id("add_student")).click();driver.findElement(By.id("loginname")).sendKeys(loginname);driver.findElement(By.id("stuname")).sendKeys(stuname);driver.findElement(By.id("password")).sendKeys(password);driver.findElement(By.id("password2")).sendKeys(password2);driver.findElement(By.id("age")).sendKeys(String.valueOf(age));driver.findElement(By.id("phone")).sendKeys(phone);driver.findElement(By.id("stunum")).sendKeys(stunum);driver.findElement(By.id("btn_sub")).click();wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("添加成功"));driver.switchTo().alert().accept();driver.switchTo().alert().dismiss();getScreenShotAs(getClass().getName());}/*** 添加用户失败测试-登录名重复* @throws IOException*/@Order(2)@ParameterizedTest@CsvSource({"超级管理员,张三,111,111,20,2011"})public void addStudentFail1(String loginname, String stuname, String password, String password2, int age, String stunum) throws IOException, InterruptedException {// 点击添加用户按钮driver.findElement(By.id("add_student")).click();// 检查添加页面是否打开driver.findElement(By.id("loginname")).sendKeys(loginname);driver.findElement(By.id("stuname")).sendKeys(stuname);driver.findElement(By.id("password")).sendKeys(password);driver.findElement(By.id("password2")).sendKeys(password2);driver.findElement(By.id("age")).sendKeys(String.valueOf(age));driver.findElement(By.id("stunum")).sendKeys(stuname);driver.findElement(By.id("btn_sub")).click();WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("添加失败,请重试"));driver.switchTo().alert().accept();getScreenShotAs(getClass().getName());}/*** 添加用户失败测试-学号重复* @throws IOException*/@Order(3)@ParameterizedTest@CsvSource({"小黑,小黑,111,111,20,10000"})public void addStudentFail2(String loginname, String stuname, String password, String password2, int age, String stunum) throws IOException, InterruptedException {// 点击添加用户按钮driver.findElement(By.id("add_student")).click();// 检查添加页面是否打开driver.findElement(By.id("loginname")).sendKeys(loginname);driver.findElement(By.id("stuname")).sendKeys(stuname);driver.findElement(By.id("password")).sendKeys(password);driver.findElement(By.id("password2")).sendKeys(password2);driver.findElement(By.id("age")).sendKeys(String.valueOf(age));driver.findElement(By.id("stunum")).sendKeys(stunum);driver.findElement(By.id("btn_sub")).click();WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("添加失败,请重试"));driver.switchTo().alert().accept();getScreenShotAs(getClass().getName());driver.navigate().back();driver.navigate().back();}
}
6.测试修改功能
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UpdateTest extends AutoTestUtils {@BeforeAllpublic static void baseSetup() {driver = getDriver();driver.get("http://82.156.151.156:8080/login.html");}/*** 更新用户成功测试--1.修改姓名* @throws IOException*/@Order(1)@ParameterizedTest@CsvSource({"小红"})public void UpdateStudentSuccess1(String stuname ) throws IOException, InterruptedException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 先登录driver.findElement(By.id("loginname")).sendKeys("admin");driver.findElement(By.id("password")).sendKeys("admin");driver.findElement(By.cssSelector("#submit")).click();// 接收弹窗WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());driver.switchTo().alert().accept();// 找到要修改的行WebElement row = driver.findElement(By.xpath("//*[@id=\"info\"]/tr[3]"));// 找到修改按钮元素WebElement deleteButton = row.findElement(By.xpath("//*[@id=\"info\"]/tr[3]/th[10]/a[1]"));// 点击修改按钮deleteButton.click();driver.findElement(By.id("stuname")).clear();driver.findElement(By.id("stuname")).sendKeys(stuname);driver.findElement(By.id("btn_sub")).click();wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("修改成功"));driver.switchTo().alert().accept();getScreenShotAs(getClass().getName());}/*** 更新用户成功测试--2.修改密码* @throws IOException*/@Order(2)@ParameterizedTest@CsvSource({"111,111"})public void UpdateStudentSuccess2(String password,String password2 ) throws IOException, InterruptedException {// 找到要修改的行WebElement row = driver.findElement(By.xpath("//*[@id=\"info\"]/tr[3]"));// 找到修改按钮元素WebElement deleteButton = row.findElement(By.xpath("//*[@id=\"info\"]/tr[3]/th[10]/a[1]"));// 点击修改按钮deleteButton.click();driver.findElement(By.id("password")).sendKeys(password);driver.findElement(By.id("password2")).sendKeys(password2);driver.findElement(By.id("btn_sub")).click();WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("修改成功"));driver.switchTo().alert().accept();getScreenShotAs(getClass().getName());}/*** 更新用户失败测试--1.未输姓名* @throws IOException*/@Test@Order(3)public void UpdateStudentFail() throws IOException, InterruptedException {// 找到要修改的行WebElement row = driver.findElement(By.xpath("//*[@id=\"info\"]/tr[3]"));// 找到修改按钮元素WebElement deleteButton = row.findElement(By.xpath("//*[@id=\"info\"]/tr[3]/th[10]/a[1]"));// 点击修改按钮deleteButton.click();driver.findElement(By.id("stuname")).clear();driver.findElement(By.id("btn_sub")).click();WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();assertTrue(alertText.contains("请先输入"));driver.switchTo().alert().accept();getScreenShotAs(getClass().getName());}//更新用户失败测试--2.登录名和学号是唯一的,在写代码时这两个值不能改,所以不用测试}
7.测试删除功能
(1)删除单条
@SpringBootTest
public class DeleteOneTest extends AutoTestUtils {@BeforeAllpublic static void baseSetup() {driver = getDriver();driver.get("http://82.156.151.156:8080/login.html");}/*** 删除单个用户测试* @throws IOException*/@Testpublic void deleteStudentOne() throws IOException, InterruptedException {// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 先登录driver.findElement(By.id("loginname")).sendKeys("admin");driver.findElement(By.id("password")).sendKeys("admin");driver.findElement(By.cssSelector("#submit")).click();// 接收弹窗WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());driver.switchTo().alert().accept();// 随便找一行删除// 找到要删除的行WebElement row = driver.findElement(By.xpath("//*[@id=\"info\"]/tr[3]"));// 找到删除按钮元素WebElement deleteButton = row.findElement(By.xpath("//*[@id=\"info\"]/tr[3]/th[10]/a[2]"));// 点击删除按钮deleteButton.click();//处理确认删除的弹框wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());driver.switchTo().alert().accept();//处理删除成功的弹窗wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("删除成功!"));driver.switchTo().alert().accept();getScreenShotAs(getClass().getName());}
}
(2)删除选中
public class DeleteMoreTest extends AutoTestUtils {@BeforeAllpublic static void baseSetup() {driver = getDriver();driver.get("http://82.156.151.156:8080/login.html");}@Testpublic void deleteMoreStudent(){// 登录之前先清空用户名和密码driver.findElement(By.id("loginname")).clear();driver.findElement(By.id("password")).clear();// 先登录driver.findElement(By.id("loginname")).sendKeys("admin");driver.findElement(By.id("password")).sendKeys("admin");driver.findElement(By.cssSelector("#submit")).click();// 接收弹窗WebDriverWait wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());driver.switchTo().alert().accept();// 找到要删除的行WebElement row1 = driver.findElement(By.xpath("//*[@id=\"info\"]/tr[2]"));// 找到这行选中框WebElement deleteButton1= row1.findElement(By.xpath("//*[@id=\"info\"]/tr[2]/th[1]"));// 点击删除按钮deleteButton1.click();// 找到要删除的行WebElement row2 = driver.findElement(By.xpath("//*[@id=\"info\"]/tr[3]"));// 找到这行选中框WebElement deleteButton2 = row2.findElement(By.xpath("//*[@id=\"info\"]/tr[3]/th[1]"));// 点击删除按钮deleteButton2.click();driver.findElement(By.xpath("//*[@id=\"delete\"]")).click(); // 点击批量删除按钮//处理确认删除的弹框wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());driver.switchTo().alert().accept();//处理删除成功的弹窗wait = new WebDriverWait(driver, 10);wait.until(ExpectedConditions.alertIsPresent());// 获取提示框的文本String alertText = driver.switchTo().alert().getText();// 验证文本是否包含了"添加成功"assertTrue(alertText.contains("选中删除成功!"));driver.switchTo().alert().accept();}
}
8.测试套件
//测试登录、列表页、查询功能、添加功能、修改功能、删除单条和删除选中功能
@Suite
@SelectClasses({LoginTest.class, ListTest.class, SelectTest.class, AddTest.class, UpdateTest.class,DeleteOneTest.class, DeleteMoreTest.class,DriverQuitTest.class })
public class RunSuite1 {
}
五、测试结果
(1)测试通过率
(2)测试截图
相关文章:

学生信息管理系统自动化测试
项目地址: http://82.156.151.156:8080/login.html 一、系统测试用例 二、测试实现过程 先是根据自己的项目设计了一个 UI 自动化测试用例, 然后根据这个测试用例使用了 selenium4自动化测试工具和 JUnit5单元测试框架结合实现的 web 自动化测试.。 测试模块划分…...
Java面向对象之toString()方法
toString()方法 toString()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址。在进行String与其它类型数据的连接操作时,自动调用toString()方法。 Date nownew Date(); System.out.println(“now”now); 相当于 System.…...
MySQL(一)
mysql简介 1、什么是数据库 ? 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后,数据管理不再仅仅…...
使用docker部署node和react应用
使用docker部署node和react应用 Docker 使开发人员能够将所有应用程序打包到容器中。这些容器可以在任何安装了 Docker 的机器上运行,并且应用程序将是相同的。这是在多个系统上运行代码库克隆的好方法,并且我们可以确保它们都是相同的。 在本文中&…...
对List集合、数组去重
前言: 还记得在2021我发布的第一篇博客就是关于数组的去重,从那一刻开始,命运的齿轮开始转动…… 扯远了哈哈哈,我重新写这篇文章只是想让去重方式更加严谨(ps:我才不会说是因为技术成长了,看不上之前写的…...

AI相机“妙鸭相机”原理分析和手动实现方案
妙鸭相机 一个通过上传大约20张照片,生成专属自拍。在2023年7月末爆火,根据36Kr报道,妙鸭相机系阿里系产品,挂靠在阿里大文娱体系下,并非独立公司。 使用方法是上传20张自拍照片,之后可以选择模板生成自己…...

关于计算机大学生秋招面试的那点事?(Golang篇)
前言; Go语言(简称Golang)越来越受到开发者的关注和欢迎。它由Google公司于2009年推出,旨在提供更好的性能和并发性能。眼下,越来越多的公司在使用它,比如著名的云计算服务商AWS,以及知名电商京…...
Windows网络自学的第一天:创建线程
CreateThread函数: 该函数用于创建一个新的线程并在其上运行指定的函数,原型如下: HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID …...

正确的 Java 异常处理
我们来谈谈痛点吧。由于我的职责,我必须使用许多不同的服务(进行编辑、进行代码审查......);不同的团队通常会编写所有这些服务,每当涉及到处理错误并从服务转发错误时,有时我的眼睛就会开始流泪。让我尝试…...

RTT(RT-Thread)时钟管理
目录 时钟管理 时钟节拍 RTT工程目录结构介绍 配置文件:rtconfig.h 获取系统节拍 获取系统节拍数函数 实例 定时器 RT_Thread定时器介绍 定时器源码分析(了解即可) rt_system_timer_init (硬件定时器初始化) rt_system_timer_thr…...

基础实验篇 | uORB消息读写与自定义实验(二)
导读 uORB是PX4/Pixhawk系统中非常重要且关键的模块之一,是用于无人机模块间通信的协议机制。本篇将详细介绍uORB并详细拆解uORB消息读写与自定义实验全流程(二)。 基础实验篇 | uORB消息读写与自定义实验(二) 01 RflySim平台的uORB消息读写…...

k8s pod数据存储Volumes
一、说在前面的话 在 Kubernetes 的 Deployment 中,您可以使用多种类型的 Volumes 来管理 Pod 中的数据。 作用是用来共享目录及配置,不用在每个pod里进行配置。 本文主要概述怎么使用HostPath、PersistentVolumeClaim、ConfigMap。 二、k8s有哪些Vol…...

ZYNQ在Petalinux系统下双网口同网段的实现
ZYNQ在Petalinux系统下双网口同网段的实现 1.开发环境 采用了赛灵思zynq xc7z100芯片,外部挂载了两个网口phy芯片(marvell 88e1510),且两个网口phy芯片公用MDIO管脚,bd配置如下: 2.问题说明 忙去了&am…...

突破传统监测模式:业务状态监控HM的新思路 | 京东云技术团队
一、传统监控系统的盲区,如何打造业务状态监控。 在系统架构设计中非常重要的一环是要做数据监控和数据最终一致性,关于一致性的补偿,已经由算法部的大佬总结过就不再赘述。这里主要讲如何去补偿?补偿的方案哪些?这就…...
7-16 验证“哥德巴赫猜想” (20 分)
7-16 验证“哥德巴赫猜想” (20 分) 数学领域著名的“哥德巴赫猜想”的大致意思是:任何一个大于2的偶数总能表示为两个素数之和。比如:24519,其中5和19都是素数。本实验的任务是设计一个程序,验证20亿以内的偶数都可以…...

GEE学习02 --设置Jupyter Notebook的打开路径
直接双击Jupyter Notebook 桌面图标运行时,打开的文件路径是默认的:C:\用户\用户名 如果使用python命令提示符打开jupyter notebook , 而我新建的GEE学习文件夹在另一个路径,可以直接修改默认的保存路径:…...

stm32与上位机电脑间最快的通信方式是什么?
对于小型多关节机械臂的控制电路设计,选择合适的通信方式可以提高MCU与上位机之间的实时性。以下是一些在STM32上常用的通信方式,你可以根据你的具体需求选择适合的: 串口通信(UART):串口通信是一种常见的…...

pytorch学习——卷积神经网络——以LeNet为例
目录 一.什么是卷积? 二.卷积神经网络的组成 三.卷积网络基本元素介绍 3.1卷积 3.2填充和步幅 3.2.1填充(Padding) 填充是指在输入数据周围添加额外的边界值(通常是零),以扩展输入的尺寸。填充可以在卷…...

stm32 mpu6050 cubemx DMP法读取角度
文章目录 前言一、相关文件二、cubemx配置三、代码变量初始化主循环 总结 前言 文件 记录使用dmp库来读取mpu6050的角度。 这是参考文件 参考1–主要参考 github参考 参考2 参考三 一、相关文件 相关文件在这里下载(未填,不过可以在上面的git中下载&a…...

.Net6 Core Web API 配置 log4net + MySQL
目录 一、导入NuGet 包 二、添加配置文件 log4net.config 三、创建MySQL表格 四、Program全局配置 五、帮助类编写 六、效果展示 小编没有使用依赖注入的方式。 一、导入NuGet 包 ---- log4net 基础包 ---- Microsoft.Extensions.Logging.Log4Net…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...