# automated-test-sample **Repository Path**: SpringIsComing/automated-test-sample ## Basic Information - **Project Name**: automated-test-sample - **Description**: 自动化测试示例 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-04-13 - **Last Updated**: 2023-04-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 自动化测试案例 **注意:自动化测试主要是把手工测试时的操作流程转成代码,交由机器自动执行。因此在自动化测试之前,手工测试所需的测试用例等准备工作仍然是必不可少的。** 本文仅对如何将手工操作转为代码的流程进行初步介绍。 ## 1. 工作流程 自动化测试的工作应按照以下步骤进行: 1. 使用Selenium IDE录制手工测试过程 2. 导出为JUnit测试用例到本项目中 3. 对自动生成的Java代码进行简单修改 4. 执行JUnit测试代码 ## 2. 工具及使用方式 > Selenium IDE是Chrome与Firefox的插件,可在此处下载并安装到浏览器:https://www.selenium.dev/selenium-ide/ > 以 https://c.runoob.com/front-end/7939/ 为例:这是一个在线的汇率换算器,我们假设需要对该应用进行测试 | 模块 | 功能 | 步骤 | |:-----------:|:------------:|:------------------------------------:| | 汇率换算 | 检测汇率换算结果是否正确 | 1.输入金额 2.选择原始货币 3.选择目标货币 4.检测汇率及换算结果 | 操作步骤: 1. 点击浏览器插件列表,找到Selenium IDE并打开 > ![](./doc/selenium-ide-1.png)![img.png](img.png) 2. 点击 创建一个新项目,然后随便输入一个项目名称,然后确定 > ![](./doc/selenium-ide-2.png) > ![](./doc/img3.png) 3. 输入页面的起始url,然后 开始录制 > ![](./doc/img4.png) > 在弹出的页面操作: > ![](./doc/img5.png) 4. 按照测试用例进行操作,操作完成后,回到Selenium IDE,点击右上角的REC按钮结束录制 ![录制完成后的结果](./doc/img6.png) 5. 对录制生成的操作列表进行修改,移除不必要的操作,对每项操作添加注释,同时添加断言。 > 在此处添加注释: > ![](./doc/img7.png) > 完成后的如下: > ![](./doc/img8.png) 6. 左上角处(图中的位置1)点击打开菜单,选择Export导出代码 > ![](./doc/img9.png) > 按下图进行勾选,点击Export按钮下载代码文件到本地 > ![](./doc/img10.png) 7. 在IDEA中打开项目,将上面的文件放到 src/test/java下,得到的代码如下: ```java // Generated by Selenium IDE import org.junit.Test; import org.junit.Before; import org.junit.After; import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.core.IsNot.not; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.Dimension; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Alert; import org.openqa.selenium.Keys; import java.util.*; import java.net.MalformedURLException; import java.net.URL; public class Sample1Test { private WebDriver driver; private Map vars; JavascriptExecutor js; @Before public void setUp() { driver = new ChromeDriver(); js = (JavascriptExecutor) driver; vars = new HashMap(); } @After public void tearDown() { driver.quit(); } @Test public void sample1() { // Test name: sample1 // Step # | name | target | value // 1 | open | /front-end/7939/ | // 打开页面 driver.get("https://c.runoob.com/front-end/7939/"); // 2 | click | id=userInput | // 点击金额输入框 driver.findElement(By.id("userInput")).click(); // 3 | type | id=userInput | 888 // 输入金额 driver.findElement(By.id("userInput")).sendKeys("888"); // 4 | click | id=select2-selectfromtime1-container | // 点击下拉框1,选择 driver.findElement(By.id("select2-selectfromtime1-container")).click(); // 5 | click | id=select2-selectfromtime2-container | // 点击下拉框2,选择 driver.findElement(By.id("select2-selectfromtime2-container")).click(); // 6 | click | id=convertResult | // 转换结果 driver.findElement(By.id("convertResult")).click(); // 7 | click | css=.card-title:nth-child(3) | // 汇率 driver.findElement(By.cssSelector(".card-title:nth-child(3)")).click(); // 8 | click | css=.text-secondary > .btn | // 点击交换按钮 driver.findElement(By.cssSelector(".text-secondary > .btn")).click(); // 9 | click | id=convertResult | // 转换结果 driver.findElement(By.id("convertResult")).click(); // 10 | click | css=.card-title:nth-child(3) | // 汇率 driver.findElement(By.cssSelector(".card-title:nth-child(3)")).click(); } } ``` 8. 对自动生成的代码做简单修改,如下(在sample/SampleVersion1Test.java): ```java package sample; import conf.DefaultConfigure; import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.junit.runner.RunWith; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import java.math.BigDecimal; import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; @RunWith(SpringRunner.class) @SpringBootTest @ContextConfiguration(classes = DefaultConfigure.class) public class SampleVersion1Test { @Autowired WebDriver driver; @Test public void sample1(){ // 打开页面 driver.get("https://c.runoob.com/front-end/7939/"); int amount = new Random().nextInt(100000); // 输入金额 WebElement userInput = driver.findElement(By.id("userInput")); userInput.clear(); userInput.sendKeys(""+amount); System.out.println("amount = " + amount); Assertions.assertEquals(""+amount, userInput.getAttribute("value")); // 4 | click | id=select2-selectfromtime1-container | // 注意,此处会发现,对于下拉框,录制工具没有把选择下拉框元素的过程录制下来,因此此处需要我们自己实现 // 回到页面,点击打开下拉框,鼠标移到某个选项上面,使用快捷键"Ctrl+Shift+C"打开审查元素的Elements标签页,可以看到对应的元素 // 此处,我们先查出所有的选项,并输出,然后选择“港币” // 我们可以发现最上层是一个带有class .select2-container的span,内部每个选项提取出的元素如下 // "
  • \n" + // " \n" + // " \n" + // " 日元 JPY\n" + // " \n" + // "
  • "; // WebElement select1 = driver.findElement(By.id("selectfromtime1")); // // 使用JavascriptExecutor执行脚本获取所有选项文本 // JavascriptExecutor js = (JavascriptExecutor) driver; // List optionTexts = (List) js.executeScript("return [...arguments[0].options].map(opt => opt.text);", select1); // // // 输出所有选项文本 // System.out.println("所有选项:"); // for (String optionText : optionTexts) { // System.out.println(optionText); // } // 点击下拉框2,选择 driver.findElement(By.id("select2-selectfromtime1-container")).click(); // 找到Select2下拉框的输入框元素 WebElement select2Input = driver.findElement(By.xpath("//input[@class='select2-search__field']")); // 使用Actions类模拟用户点击输入框打开下拉列表 Actions actions = new Actions(driver); actions.click(select2Input).perform(); // // 输出所有选项,写代码时用,后期可删除 // List options = driver.findElements(By.cssSelector("span.select2-container li.select2-results__option")); // for (WebElement option : options) { // System.out.println(option.getText()); // } // 找到下拉列表中需要选择的选项元素 WebElement optionElement = driver.findElement(By.xpath("//li[./span/span[text()='英镑 GBP']]")); actions.moveToElement(optionElement).click().perform(); // 使用JavascriptExecutor执行点击操作选择选项 // JavascriptExecutor js = (JavascriptExecutor) driver; // js.executeScript("arguments[0].click();", optionElement); // 5 | click | id=select2-selectfromtime2-container | // 点击下拉框2 driver.findElement(By.id("select2-selectfromtime2-container")).click(); // 重复以上步骤,此时选择“欧元” // 找到Select2下拉框的输入框元素 select2Input = driver.findElement(By.xpath("//input[@class='select2-search__field']")); // 使用Actions类模拟用户点击输入框打开下拉列表 actions.click(select2Input).perform(); optionElement = driver.findElement(By.xpath("//li[./span/span[text()='欧元 EUR']]")); // js.executeScript("arguments[0].click();", optionElement); actions.moveToElement(optionElement).click().perform(); // 汇率,同转换结果,去掉点击,提取数据并输出 String rateString = driver.findElement(By.cssSelector(".card-title:nth-child(3)")).getText(); // System.out.println("rateString = " + rateString); BigDecimal rate = new BigDecimal(rateString.substring(3)); // 转换结果,去掉点击,提取数据并输出 String convertResult = driver.findElement(By.id("convertResult")).getAttribute("value"); // 写代码时,可以打印相关的内容,后期需要改为Assert语句 // System.out.println("convertResult = " + convertResult); Pattern pattern = Pattern.compile("^(\\d+\\.?\\d*).*?(\\d+\\.?\\d*).*$"); // 验证格式 Assertions.assertTrue(convertResult.matches(pattern.pattern())); Matcher matcher = pattern.matcher(convertResult); if (matcher.find()) { BigDecimal from = new BigDecimal(matcher.group(1)); BigDecimal to = new BigDecimal(matcher.group(2)); Assertions.assertEquals(from, new BigDecimal(amount)); // 这个网站的汇率精确度较低,所以检测 expectTo 和 to 会发现不一致 // BigDecimal expectTo = from.multiply(rate).setScale(2,BigDecimal.ROUND_HALF_UP); // Assertions.assertEquals(expectTo,to); // 此处改为检测汇率 BigDecimal expectRate = to.divide(from,4,BigDecimal.ROUND_HALF_UP); Assertions.assertEquals(expectRate, rate); } } } ``` 9. 对于一些经常使用的页面,应当提取并创建Page类,方便后续其它测试的编写。 ## 3. 其它 * 可以选择使用Chrome或Firefox,需要下载对应的driver,在conf.DefaultConfigure中WebDriverFactory的参数true为Chrome,false为Firefox浏览器 ```java @Bean public FactoryBean webDriverFactory(){ return new WebDriverFactory(false); } ``` > https://chromedriver.storage.googleapis.com/index.html > https://github.com/mozilla/geckodriver/releases > https://firefox-source-docs.mozilla.org/testing/geckodriver/Support.html > 注意driver版本要和你的浏览器版本匹配, driver要加入到环境变量PATH中 * 关于文件的上传与下载: - 上传 用sendKeys("文件路径")即可 - 下载默认会下载到download目录下 然后通过读取已下载的文件进行验证处理。