特殊元素定位-->创建WebDriver对象-->WebDriver对象常用API-->创建maven项目-->添加基本依赖(testng,selenium,poi-ooxml,dom4j,log4j,reportng,mail,mysql-connector-java,maven-surefire-plugin)-->添加base父类-->测试用例,写一个解析excel工具类-->编写测试方法代码-->编写uilibraryutil工具类-->做日志-->做检查点-->集成surefire插件-->自定义监听器-->testng测试报告页面修改-->邮件服务-->持续集成jenkins-->项目总结
-- 元素定位
-- iframe窗口切换使用switchTo().frame("bframe")1import org.openqa.selenium.By;import org.testng.annotations.Test;import com.mingmenban.testng.Base;public class IframeDemo extends Base { @Test public void iframe(){ driver.get("file:///D:/zuoye/a.html"); driver.findElement(By.id("aa")).sendKeys("aa"); driver.switchTo().frame("bframe"); driver.findElement(By.id("bb")).sendKeys("bb"); driver.switchTo().frame("cframe"); driver.findElement(By.id("cc")).sendKeys("cc"); }}2html文件<html> <head> </head> <body> <form> 这是a.html:<input type="text" id="aa" value=""/> <iframe src="./b.html" id="bframe" width="1000px" height="600px"></iframe> </form> </body></html><html> <head> </head> <body> <form> b.html:<input type="text" id="bb"/> <iframe src="./c.html" id="cframe" width="800px" height="400px"></iframe> </form> </body></html><html> <head> </head> <body> <form> етЪЧc.html:<input type="text" id="cc"/> </form> </body></html>-- 多窗口切换window当要操作另外一个窗口的元素时,一定要注意先切换窗口切换方式跟切换iframe类似传入要操作窗口的name或者句柄handle值:如何获取到窗口句柄driver.getwindowHandle:获取当前操作窗口句柄driver.getwindowHandles:获取测试时打开的所有窗口句柄1import java.util.Set;import org.openqa.selenium.By;import org.testng.annotations.Test;import com.mingmenban.testng.Base;public class WindowDemo extends Base { @Test public void window(){ driver.get("file:///D:/zuoye/a.html"); String currentHandle=driver.getWindowHandle(); System.out.println(currentHandle); driver.findElement(By.id("bb")).click(); driver.findElement(By.id("cc")).click(); driver.findElement(By.id("aa")).sendKeys("aa"); Set<String>handles=driver.getWindowHandles(); for (String handle : handles) {//遍历句柄,如果拿到窗口路径,包含contains页面,执行输入 if(driver.switchTo().window(handle).getCurrentUrl().contains("b.html")){ driver.findElement(By.id("bb")).sendKeys("bb"); }else if(driver.switchTo().window(handle).getCurrentUrl().contains("c.html")){ driver.findElement(By.id("cc")).sendKeys("cc"); } } }}2<html> <head> <title>a.html</title> </head> <body> <form> 这是a.html:<input type="text" id="aa" value=""/> <a id="bb" href="./b.html" target="_blank">跳到b页面</a> <a id="cc" href="./c.html" target="_blank">跳到c页面</a> </form> </body></html><html> <head> <title>b.html</title> </head> <body> <form> 这是b.html:<input type="text" id="bb"/> </form> </body></html><html> <head> <title>c.html</title> </head> <body> <form> 这是c.html:<input type="text" id="cc"/> </form> </body></html>-- 获取元素标签名/属性值/文本内容getTagName():获取当前元素的标签名getAttribute("属性名"):根据属性名去获取属性值getText:获取当前元素的文本值 -- 元素是否显示/可操作/被选中isDisplaya():判断当前元素是否显示isEnabled():判断当前元素是否可操作isSelected():判断当前元素是否被选中-- 页面元素常见事件click():触发当前元素的点击事件sendKeys():往文本框一类元素中写入内容-- 创建WebDriver对象WebDriver driver=new FirefoxDriver()WebDriver driver=new InternetExplorerDriver()WebDriver driver=new ChromeDriver()-- WebDriver对象常用APIdriver.get(String url):访问指定url页面driver.getCurrentUrl():获取当前页面的url地址driver.getTitle():获取当前页面标题driver.getPageSource():获取当前页面源代码driver.quite():关闭驱动对象以及所有的相关窗口driver.close():关闭当前窗口driver.findElement(by):根据by对象获取元素(单个元素)driver.findElements(by):根据by对象获取元素(元素集合)driver.getWindowHandle():返回当前页面句柄driver.getWindowHandles():返回所有由驱动对象打来页面的句柄。页面不同,句柄不一样driver.navigate():此方法可以获取Navigation--浏览器导航操作对象,通过navigation可以完成浏览器回退或者导航到指定url页面等操作driver.manage():此方法可以获取option--浏览器操作菜单操作对象,通过此对象可以完成浏览器的cookie设置driver.manage().timeouts():此方法可以获取timeout--驱动超时对象,可进行多种场景的等待超时设置driver.manage().window():此方法可以获取window--当前窗口对象,可进行窗口大小设置driver.switchTo():此方法可以获取到targetlocator对象,通过此对象的相关函数可以传递自动化指令到iframe或者不同的window对象例子public class ElementProcess extends Base{ @Test public void test(){ driver.get("http://www.baidu.com"); System.out.println("元素的标签名:"+driver.findElement(By.id("kw")).getTagName()); System.out.println("元素的属性值:"+driver.findElement(By.id("kw")).getAttribute("id")); System.out.println("元素的文本值:"+driver.findElement(By.id("kw")).getText()); System.out.println("元素是否可编辑:"+driver.findElement(By.id("kw")).isEnabled()); System.out.println("元素是否可见:"+driver.findElement(By.id("kw")).isDisplayed()); System.out.println("元素是否被选中:"+driver.findElement(By.id("kw")).isSelected()); driver.get("file:///D:/zuoye/a.html"); Select select=new Select(driver.findElement(By.tagName("select"))); List<WebElement>list=select.getOptions(); System.out.println("元素是否被选中:"+list.get(1).isSelected()); System.out.println("当前页面的url地址"+driver.getCurrentUrl()); System.out.println("当前页面标题"+driver.getTitle()); System.out.println("当前页面的源代码"+driver.getPageSource()); }}-- timeouts1,thread.sleep(3000);线程等待2,driver.manage().timeouts().pageLoadTimeout(3, TimeUnit.SECONDS);页面等待3,timeouts.implicitlyWait(3, TimeUnit.SECONDS);隐式等待(针对全局元素)4,WebDriverWait;显示等待(针对指定元素) public WebElement getElement(WebDriver driver,By by){ WebDriverWait wait=new WebDriverWait(driver, 30); WebElement element=wait.until(new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver driver){ return driver.findElement(by); } }); return element;}-- 特殊元素的操作-- select下拉框下拉框处理类:Select如果页面元素是一个下拉框,我们可以将此web元素封装为Select对象Select select=new Select(webElement element);select.getOptions():获取所有选项select.selectByIndex(index);根据所有选中对应元素select.selectByValue(value);选择指定value值对应的选项select.selectByVisibleText(text);选中文本值对应的选项isMultiple();判断是不是多选select.deselectAll();取消所有选中的选项@Test public void test() throws InterruptedException{ driver.navigate().to("file:///D:/zuoye/a.html"); WebElement webElement=driver.findElement(By.tagName("select")); Select select=new Select(webElement); System.out.println("是否为多选框"+select.isMultiple()); select.selectByIndex(1); Thread.sleep(1000); select.selectByValue("5"); Thread.sleep(1000); select.selectByVisibleText("上海市"); Thread.sleep(1000); List<WebElement>options=select.getOptions(); for (WebElement option : options) { System.out.println("value:"+option.getAttribute("value")+"text:"+option.getText()); } }-- alert confirm等模态框的操作Alert alert=driver.switchTo.alert();alert.getText();获取警告中的提示信息alert.accept();确认alert.dismiss();取消public class SelectDemo2 extends Base{ @Test public void test() throws InterruptedException{ driver.navigate().to("file:///D:/zuoye/a.html"); Alert alert=driver.switchTo().alert(); alert.getText(); alert.accept();// alert.dismiss();}}-- 时间控件直接定位元素,写入时间数据-- javasccript调用在操作页面元素的时候,如果通过selenium的api来完成就没有必要通过js来实现dom操作但是有些特殊情况下操作某些页面元素在selenium的api完成不了的情况,可以通过执行js脚本来完成1,比如上面的时间插件只允许通过选择,不允许输入,那么调用sendkeys写入数据就不行就可以通过执行js来操作这个元素2,富文本编辑器里输入内容JavascriptExecutor javascriptExecutor=(JavascriptExecutor) driver;javascriptExecutor.executeScript("...");例如public class SelectDemo3 extends Base{ @Test public void test() { driver.navigate().to("file:///D:/zuoye/a.html"); JavascriptExecutor javascriptExecutor=(JavascriptExecutor) driver; javascriptExecutor.executeScript("document.getElementById('time').value='2018-04-13'"); }} -- 鼠标,键盘事件 Actions:在操作一个页面需要一连串的操作才能完成 actions.clickAndHold(from).moveToElement(to).release().build().perform(); 测试地址:http://www.treejs.cn/v3/demo/cn/exedit/drag.html例子import org.openqa.selenium.By;import org.openqa.selenium.WebDriver;import org.openqa.selenium.WebElement;import org.openqa.selenium.interactions.Actions;import org.openqa.selenium.support.ui.ExpectedCondition;import org.openqa.selenium.support.ui.WebDriverWait;import org.testng.annotations.Test;import com.mingmenban.testng.Base;public class ActionsDemo extends Base { @Test public void test(){ driver.get("http://www.treejs.cn/v3/demo/cn/exedit/drag.html"); Actions actions=new Actions(driver); WebElement from=getElement(driver,By.id("treeDemo_2_span")); WebElement to=getElement(driver,By.id("treeDemo_11_span")); actions.clickAndHold(from).moveToElement(to).release().build().perform(); //build建立动作,perform演示 } public WebElement getElement(WebDriver driver, final By by){ WebDriverWait wait=new WebDriverWait(driver, 30); WebElement element=wait.until(new ExpectedCondition<WebElement>() { public WebElement apply(WebDriver driver){ return driver.findElement(by); } }); return element;} }-- 文件上传1<input type="file" id="fileuploader">因为上传文件会需要打开window的文件选择窗口,而selenium是无法操作这个窗口的,所以解决办法为:调用sendkeys写入文件的路径2文件上传是使用第三方的空间,并且不是input元素,那么这种情况就很棘手必须要使用一些第三方的框架,比如autoid等来完成public class FileDemo2 extends Base { @Test public void test(){ driver.get("file:///D:/zuoye/a.html"); driver.findElement(By.id("test")).sendKeys("F:\\mysql.png"); }}-- 创建maven项目1.创建项目:phoneix_web2.添加基本依赖:testng,selenium,poi-ooxml,dom4j3.配置xml文件:testng.xml4.添加测试用例5.写一个工具类用于解析excel1.创建项目:phoneix_web右键new选择other-输入maven选择maven project-next勾选create a simper project-next 填写group id,artifact id -finish2.添加基本依赖,pom.xml文件依赖地址:https://mvnrepository.com/artifact/log4j/log4j/1.2.17testng <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.8.8</version> <scope>test</scope> </dependency>selenium <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.5.1</version> </dependency>poi-ooxml(解析excel) <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.15</version> </dependency>dom4j <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency>3.testng.xml文件<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"><suite name="后台管理系统"> <test name="自动化测试"> <classes> <class name="包名地址"></class> </classes> </test> <parameter name="browserType" value="firefox"></parameter> <parameter name="driverPath" value="src/test/resources/geckodriver.exe"></parameter> <parameter name="seleniumVersion" value="3.X"></parameter></suite>4.添加一个base父类,浏览器的选择5.添加测试用例在src/test/resources添加测试用例的excel文件6.写一个工具类用于解析excel方法用静态函数static表示,方便下面调用方法的时候可以使用类名直接调用;函数解析excel返回的是行列数据的二维数值,所以函数返回值用object[][]表示;workbookfactory.create传入输入流对象创建工作簿workbook;输入流对象ExcelUtil.class.getResourceAsStream(path);路径为/register.xlsx;获取工作簿的表单,work.getsheetat(0);获取表单的行,sheet.getrow(0);获取表单的列,row.getcell(0);7.编写测试方法,@test常用的方法采用封装思想放在父类比如浏览器的选择base方法比如测试地址的输入to方法,测试地址url放在properties文件下然后写一个工具类,解析properties里面的数据po编程,page object,把页面元素抽取出来,面向对象编程获取页面元素属性做日志8.执行testng.xml练习1,调用的父类和解析xml,properties文件方法父类,封装driver,to url, 关键字获取locator方法public class Base { public static WebDriver driver; @BeforeSuite @Parameters({"browserType","driverPath","seleniumVersion"}) public void setup(String browserType,String driverPath, String seleniumVersion){ if("firefox".equalsIgnoreCase(browserType)){ if("3.X".equals(seleniumVersion)){ System.setProperty("webdriver.gecko.driver", driverPath); } driver=new FirefoxDriver(); }else if("IE".equalsIgnoreCase(browserType)&&"3.X".equals(seleniumVersion)){ System.setProperty("webdriver.ie.driver",driverPath); DesiredCapabilities capabilities=new DesiredCapabilities(); capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true); capabilities.setCapability(InternetExplorerDriver.IGNORE_ZOOM_SETTING, true); capabilities.setCapability(InternetExplorerDriver.INITIAL_BROWSER_URL, "http://www.baidu.com"); driver=new InternetExplorerDriver(); }else if("chrome".equalsIgnoreCase(browserType)&&"3.X".equals(seleniumVersion)){ System.setProperty("webdriver.chrome.driver",driverPath); driver=new ChromeDriver(); } } // 时间等待30s直到找到元素停止等待 根据传入的关键字传入locator public WebElement getElement(String keyword) { final Locator locator=UILibraryUtil.pageLocatorsMap. get(this.getClass().getName()).get(keyword); WebDriverWait wait = new WebDriverWait(driver, 30); WebElement element = wait.until(new ExpectedCondition<WebElement>() { public WebElement apply(WebDriver driver) { String by=locator.getBy(); String value=locator.getValue(); if("id".equals(by)){ return driver.findElement(By.id(value)); }else if("xpath".equals(by)){ return driver.findElement(By.xpath(value)); }else if("name".equals(by)){ return driver.findElement(By.name(value)); }else if("className".equals(by)){ return driver.findElement(By.className(value)); }else if("tagName".equals(by)){ return driver.findElement(By.tagName(value)); }else if("cssSelector".equals(by)){ return driver.findElement(By.cssSelector(value)); }else if("linkText".equals(by)){ return driver.findElement(By.linkText(value)); }else if("partialLinkText".equals(by)){ return driver.findElement(By.partialLinkText(value)); } return null; } }); return element; } //返回集合 public List<WebElement> getElements(String keyword) { final Locator locator=UILibraryUtil.pageLocatorsMap.get(this.getClass().getName()).get(keyword); WebDriverWait wait = new WebDriverWait(driver, 30); List<WebElement> elements = wait.until(new ExpectedCondition<List<WebElement>>() { public List<WebElement> apply(WebDriver driver) { String by=locator.getBy(); String value=locator.getValue(); if("xpath".equals(by)){ return driver.findElements(By.xpath(value)); }else if("name".equals(by)){ return driver.findElements(By.name(value)); }else if("className".equals(by)){ return driver.findElements(By.className(value)); }else if("tagName".equals(by)){ return driver.findElements(By.tagName(value)); }else if("cssSelector".equals(by)){ return driver.findElements(By.cssSelector(value)); }else if("linkText".equals(by)){ return driver.findElements(By.linkText(value)); }else if("partialLinkText".equals(by)){ return driver.findElements(By.partialLinkText(value)); } return null; } }); return elements; } /**访问对应的url * @param url */ public void to(String url){ driver.navigate().to(url); } /** * 浏览器最大化 */ public void maximize() { driver.manage().window().maximize(); } /** * 浏览器前进 */ public void foreward() { driver.navigate().forward(); } /** * 浏览器后退 */ public void back(){ driver.navigate().back(); } }解析properties里面的数据,解析properties工具类public class PropertiesUtil { public static Properties urlProperties; static { if (urlProperties == null) { loadUrlProperties(); } } public static void loadUrlProperties() { urlProperties = new Properties(); try { urlProperties.load(PropertiesUtil.class.getResourceAsStream("/url.properties")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}测试web页面,元素id等保存的文件,uilibrary.xml文件<?xml version="1.0" encoding="UTF-8"?><pages><!-- locator:描述的是元素的定位信息;by:指定的是根据什么来定位元素;value:对应的值;desc:描述的是对应页面上的哪个元素 --> <page class="com.ningmengban.phoenix.RegisterPage" desc="注册页面"> <locator by="id" value="mobilephone" desc="用户名输入框"></locator> <locator by="id" value="password" desc="密码输入框"></locator> <locator by="id" value="pwdconfirm" desc="重复密码输入框"></locator> <locator by="id" value="signup-button" desc="注册按钮"></locator> <locator by="xpath" value="/html/body/div[2]/div/form/div[4]/div/label/p" desc="错误信息提示元素"></locator> </page> <page class="com.ningmengban.phoenix.loginPage" desc="登录页面"> <locator by="id" value="mobilephone" desc="用户名输入框"></locator> <locator by="id" value="password" desc="密码输入框"></locator> <locator by="id" value="pwdconfirm" desc="重复密码输入框"></locator> <locator by="id" value="signup-button" desc="注册按钮"></locator> <locator by="xpath" value="/html/body/div[2]/div/form/div[4]/div/label/p" desc="错误信息提示元素"></locator> </page></pages>测试web页面,url保存的文件,url.propertiesregister.Url=http://8080/lmcanon_web_auto/mng/register.htmllogin.Url=http://8080/lmcanon_web_auto/mng/login.html2,测试方法public class RegisterPage extends Base { @Test(dataProvider = "registerDatas") public void test1(String mobilephone, String password, String pwdconfirm, String expected) { to(PropertiesUtil.urlProperties.getProperty("register.Url")); // 获取测试页面 // 定位到用户名输入框 getElement("用户名输入框").sendKeys(mobilephone); // 定位到密码输入框 getElement("密码输入框").sendKeys(password); // 定位到重复密码输入框 getElement("重复密码输入框").sendKeys(pwdconfirm); // 点击登录按钮 getElement("注册按钮").click(); // 断言来判断实际错误提示信息是否与实际期望值一致 String actual = getElement("错误信息提示元素").getText(); boolean flag = expected.equals(actual); Assert.assertTrue(flag); } @DataProvider public Object[][] registerDatas() throws Exception { Object[][] datas = ExcelUtil.read("/register.xlsx", 2, 8, 1, 4); return datas; }}3,testng.xml<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"><suite name="后台管理系统"> <test name="元素测试"> <classes> <class name="com.ningmengban.phoenix.RegisterPage"></class> </classes> </test> <parameter name="browserType" value="firefox"></parameter> <parameter name="driverPath" value="src/test/resources/geckodriver.exe"></parameter> <parameter name="seleniumVersion" value="3.X"></parameter></suite>4.相关依赖和浏览器驱动文件和相关文件解析工具类准备,测试用例文档准备excel解析工具类,ui解析工具类,properties解析工具类testng,selenium,poi-ooxml,dom4j-- 71日志记录日志,记录自动化测试过程中的日志添加日志依赖创建日志配置文件,log4j.properties-- 另外封装日志为了方便元素操作记录日志,可以另行封装元素的操作方法,在方法内做日志就能达到统一做日志的效果,一劳永逸1,sendKeyslogger.info("输入数据:"+value);2,getTextlogger.info("获取元素本文内容,值为:"+text);3,clicklogger.info("触发点击事件");-- 封装日志为了方便元素操作记录日志,可以封装元素的操作方法,在方法内做日志就能达到统一做日志的效果,一劳永逸做法:采取在findelement/findElements方法内做日志做法对整个unitl方法做捕捉处理,记录日志信息。初始化日志内容String tips="获取元素列表:{'by','"+locator.getBy()+"'},{'value','"+locator.getValue()+"'}");成功情况:tips拼接【成功】错误情况:tips拼接【失败】--72检查点设计断言类Assertion,处理多种场景断言1,assertTextPresent:断言期望值出现在了页面2,assertTextNotPresent3,assertTextPresentPrecesion断言期望值与实际值一致4,assertTextNotPresentPrecesion5,assertElementEditable断言期望值是否可编辑6,assertElementNotEditable7,assertElementAttributeValueEquals8,assertElementAttributeValueNotEquals9,assertAlertTextContains10,assertURLContains--73集成surefire插件为了后期集成jenkins等自动化平台,我们必须要保证自己的脚本可以通过命名执行pom.xml文件下<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.7.1</version> <configuration> <systemPropertyVariables> <org.uncommons.reportng.escape-output>false</org.uncommons.reportng.escape-output> </systemPropertyVariables> <testFailureIgnore>true</testFailureIgnore> <argLine> -Dfile.encoding=UTF-8 </argLine> <suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles> </configuration> </plugin> </plugins> </build> -- testng提供的测试报告报表文件在项目底下test-output目录:index.htmltestng自带的报表不够酷炫美观,我们可以集成reportng,它可以很好地适配testng,提供更美观的测试报告-- reportng依赖<dependency> <groupId>org.uncommons</groupId> <artifactId>reportng</artifactId> <version>1.1.4</version> <scope>test</scope></dependency>在testng.xml中添加监听器,此监听器是用来渲染报表用的<listeners> <listener class-name="org.uncommons.reportng.HTMLReporter"></listener></listeners>生成报告渲染失败时,可能是testng没有达到6.9.5以上,也可以通过下载guicejar包处理,最好是下载jar包<dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>3.0</version></dependency>maven私服日志路径:file:///E:/workspace_java_term2/phoenix_web/target/surefire-reports/html/index.html选择testng构建时,查看测试报告路径file:///E:/workspace_java_term2/phoenix_web/test-output/index.html选择maven构建时,查看测试报告路径file:///E:/workspace_java_term2/phoenix_web/target/surefire-reports/index.htmlreportng生成测试报告位置file:///E:/workspace_java_term2/phoenix_web/target/surefire-reports/html/index.html-- 74下载apach以管理员身份打开命令提示符CD命令E:\apache2.2\binhttpd.exe -k startE:\workspace_java_term1\firefoxDemo\target\surefire-reportsE:/Apache2.2/Apache2.2-- 75测试报告添加错误截图信息1.获取截图文件File image=ScreenUtil.taskScreenShot(screenShotDir);//保存目录2.获取图片的访问url路径String path=image.getAbsolutePath();String accessPath=path.replace(path.substring(0, outputDir.lastIndexOf("screenshot")),"http://localhost/").replace("\\","/");3.调用report的log方法记录下载截屏图片的访问路径,报表处理类就能取这个信息渲染出来Reporter .log("<img src='"+accessPath+"'hight='100'width='100'><a href='"+accessPath+"'target='_blank'>点击查看大图</a></img>");4.修改文件reportng.properties,添加三对键值对.m2目录log=Log Infoscreenshot=Screen Shotduratain=Duration5.修改results.html.vm在测试类的名字后面加集成时间,日志,截屏 <td colspan="3" class="group">$testClass.name</td> <td colspan="3" class="group">$messages.getString("duration")</td> <td colspan="3" class="group">$messages.getString("log")</td> <td colspan="3" class="group">$messages.getString("screenshot")</td>5.class-results.html.vm #if ($meta.shouldEscapeOutput()) $utils.escapeHTMLString($line)<br /> #else $line #end 修改为 #if ($meta.shouldEscapeOutput()) $utils.escapeHTMLString($utils.removeImage($line))<br />#else $utils.removeImage($line)<br/>#end新增一列,添加以下内容:<td class="screenshot"> #set ($output = $utils.getTestOutput($testResult)) #if ($output.size() > 0) <div class="screenshotimage"> #foreach( $line in $output ) #if ($meta.shouldEscapeOutput()) $utils.escapeHTMLString($utils.getImageString($line))<br /> #else $utils.getImageString($line)<br /> #end #end </div> #end </td> 6.上面出现的两个方法getImageString,removeImage。 就是提取含有img标签的字符串和去除带有img标签的字符串修改ReportNGUtils.java 新增两个getImageString,removeImage方法 public String getImageString(String s){ String regex = "<img .*>.*</img>"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(s); if(matcher.find()){ return matcher.group(0); } return ""; } public String removeImage(String s){ String regex = "<img .*>.*</img>"; return s.replaceAll(regex, ""); }-- 77发送邮件添加mail依赖<dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.5.0-b01</version></dependency>写一个邮件工具类package com.mingmengban.phoenix.util;import java.util.Properties;import javax.activation.DataHandler;import javax.activation.DataSource;import javax.activation.FileDataSource;import javax.mail.Address;import javax.mail.Authenticator;import javax.mail.BodyPart;import javax.mail.Multipart;import javax.mail.PasswordAuthentication;import javax.mail.Session;import javax.mail.Store;import javax.mail.Transport;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeBodyPart;import javax.mail.internet.MimeMessage;import javax.mail.internet.MimeMultipart;import org.apache.log4j.Logger;import java.io.File;import java.util.ArrayList;import java.util.List;import com.ningmengban.phoenix.mail.Auth;import com.sun.mail.smtp.*;public class EmailUtil { private static Logger log = Logger.getLogger(EmailUtil.class); public static void main(String[] args) { File logFile = new File("target/surefire-reports/phoenix_web.log"); File testCase = new File("src/test/resources/register.xlsx"); List<File> files = new ArrayList<File>(); files.add(logFile); files.add(testCase); EmailUtil.sendmessage("101@163.com", "101@163.com", "smtp.163.com", "25", "101@163.com","101@qq.com", "测试报告", "http://localhost/html/index.html",files); } /** * * @param userName 发送邮箱账号 xxx@xxx.com形式 * @param passWord 发送邮件密码 * @param smtpHost stmp服务器地址 * @param smtpPort smtp服务器端口 * @param from 发件人地址 * @param tos 收件人地址 * @param title 标题 * @param content 内容 */ public static void sendmessage(String userName,String passWord,String smtpHost,String smtpPort,String from,String tos ,String title,String content,List<File> fileList) { Properties smtpProper=setSmtp(smtpHost, smtpPort, userName, passWord); Auth authenticator=new Auth(userName, passWord); try { //创建session实例 Session session=Session.getInstance(smtpProper, authenticator); MimeMessage message=new MimeMessage(session); session.setDebug(true); //设置from发件人邮箱地址 message.setFrom(new InternetAddress(from)); //收件人to LIST ArrayList<Address> toList=new ArrayList<Address>(); //收件人字符串通过,号分隔收件人 String[] toArray=tos.split(","); for (int i = 0; i < toArray.length; i++) { String str = toArray[i]; toList.add(new InternetAddress(str)); } //将收件人列表转换为收件人数组 Address[] addresses=new Address[toList.size()]; addresses=toList.toArray(addresses); //设置to收件人地址 message.setRecipients(MimeMessage.RecipientType.TO,addresses); //设置邮件标题 message.setSubject(title); Multipart multipart = new MimeMultipart(); //添加邮件正文 BodyPart contentPart = new MimeBodyPart(); contentPart.setContent(content,"text/html;charset=UTF-8"); multipart.addBodyPart(contentPart); //添加附件 if(fileList!=null&&fileList.size()>0){ for (File file : fileList) { BodyPart attachmentPart = new MimeBodyPart(); DataSource ds = new FileDataSource(file); attachmentPart.setDataHandler(new DataHandler(ds)); attachmentPart.setFileName(file.getName()); multipart.addBodyPart(attachmentPart); } } //设置邮件内容 message.setContent(multipart); //Transport.send(message); Transport transport=session.getTransport(); transport.connect(smtpHost,userName, passWord); //发送邮件 transport.sendMessage(message,addresses); log.info("发送邮件成功!"); } catch (Exception e) { // TODO: handle exception log.error("发送邮件失败!"); e.printStackTrace(); } } private static Properties setSmtp(String smtpHost,String smtpPort,String userName,String passWord) { //创建邮件配置文件 Properties maiProperties=new Properties(); //配置smtp发件服务器 maiProperties.put("mail.transport.protocol", "smtp"); //配置smtp服务器 maiProperties.put("mail.smtp.host", smtpHost); //配置smtp服务器端口 maiProperties.put("mail.smtp.port", smtpPort); //配置smtp用户名 maiProperties.put("mail.user", userName); //配置smtp身份验证 maiProperties.put("mail.smtp.auth", "true"); return maiProperties; }}备注1.创建maven项目:phoneix_web2.集成testng:添加基本依赖,testng,selenium,poi-ooxml,dom4j3.配置xml文件:testng.xml4.添加一个base父类,5.根据需求编写测试用例excel文件:register.xlsx6.写一个工具类用于解析excel,利用poi技术读excel数据实现数据驱动测试7.根据测试用例编写测试代码:8.完善父类base逻辑,提供navigate对象和window对象的常用方法9.优化元素等待10.po模式11.做日志,对日志进行优化,在方法内做日志和另行封装元素的操作方法做日志12.检查点,设计断言assertion,处理多种断言场景13.集成surefire插件14.测试报告reportng,guicejar依赖15.testng提供的测试报告修改模板16.发送邮件-78 jenkins环境搭建下载war包;jenkins.war执行java-jar jenkins.war或者部署到tomcat访问http://localhost:8080下载tomcat,apache-tomcat-6.0.531.jenkins.war放在apache-tomcat-6.0.53\webapps文件夹下面2.-78.79.80.81.82-jenkins项目集成讲解,javac环境配置不行,待处理操作记录笔记。-83总结1.maven项目?搭建环境需要创建maven项目因为maven项目可以更方便的管理项目的第三方依赖。中央仓库,本地仓库通过preference-user setting,查看文件路径,如果需要修改路径,需要下载maven插件,在指定插件的文档保存地址dependency。pom.xml文件的结构要清楚2.testng?更方便的管理咱们的用例,并且testng提供了多种测试场景实现。3.selenium-java?selenium是一套web自动化的框架技术。而我们要完成web自动化就需要用到他的类来处理4.poi-ooxml?这一套框架是专门用来处理excel的,通过解析excel拿到用例里面的测试数据从而成功实现了数据驱动测试。5.dom4j?当时引入这一套框架是想基于po模式编程,将页面的元素信息与代码实现解耦。6.log4j?是一个日志框架,对于自动化测试过程中的一些关键操作,通过做日志可以更好的跟踪和定位咱们自动化测试流程中出现的问题。7.reportng?reportng是一套报表框架,他是基于velocity实现的一套模板技术。引入它可以帮咱们生成酷炫的测试报表。8.mail?基于java的mail框架实现邮件服务,使得自动化测试执行完相关项目组人员能够看到邮件中的测试结果。9.mysql-connector-java?这是一个mysql数据库连接的驱动包。如果我们在自动化测试过程中需要操作数据库,那咱们就需要用到这个驱动包来连接数据库。10.maven-surefire-plugin?使得我们可以通过执行maven命令来完成自动化框架的测试。同时也方便了我们后面的持续集成到某些自动化平台,比如jenkins。参数化实现的三种方式1.testng工厂模式2.testng的dataProvider 数据提供者3.testng的@parameters,参数化设置po模式编程解耦页面元素自定义了一个uilibraryutil.xml,定义了page元素指定class属性将底下的所有locator跟页面绑定起来定义了locator元素,将页面封装为locator对象,by:根据什么方式来定位元素,value:id、xpath等的值,desc:元素关键字uilibraryutil是一个工具类,一次性加载所有的页面元素到内存页面元素解耦(把元素信息解开耦合放在配置文件里xml)Map<string,Map<string,locator>>等待处理Thread.sleep(3000);傻瓜式等待,线程等待,会一直等待,直到时间到期driver.manage().timeouts().implicitlyWait(30,TimeUnit.second);隐式等待,智能等待,但是是全局的方式WebDriverWait wait = new WebDriverWait(driver, 30);显示等待,智能等待,默认隔0.5秒扫描一次操作元素时,统一做日志自己封装一套元素操作方法,在自己的方法里面去记录元素的操作日志,这样就完美的解决了统一做日志的问题实现一套实现检查点技术assertion将平时功能测试中判断一个功能是否正常的依据,转换为代码去实现平切在考虑这个方法实现之前,要想一下这个依据是否方便用代码去实现自定义监听器通过监听器监听失败的用例,截图保存到文件系统,然后搭建apache服务器,我们通过http url可以访问到我们的文件修改reportng报表的模板,添加一列截图邮件服务测试套件完成时发送邮件,在base中的teardown标注了@aftersuite方法中加了发送邮件的方法邮件内容,测试报表的访问路径+日志+测试用例附件持续集成jenkins1.jenkins环境搭建(部署war包到tomcat,在war包目录底下执行java-jar jenkins.war)2.安装默认推荐的插件3.修改用户登录密码4.通过全局配置设置了5.新建任务6.配置任务:集成svn,修改build信息,设置触发器实现定时构建