2018-04-18web自动化学习心得(2)

特殊元素定位-->创建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")
1
import 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:获取测试时打开的所有窗口句柄
1
import 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对象常用API
driver.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());    
    }
}
-- timeouts
1,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_web
2.添加基本依赖:testng,selenium,poi-ooxml,dom4j
3.配置xml文件:testng.xml
4.添加测试用例
5.写一个工具类用于解析excel


1.创建项目:phoneix_web
右键new选择other-输入maven选择maven project-next勾选create a simper project-
next 填写group id,artifact id -finish
2.添加基本依赖,pom.xml文件
依赖地址:https://mvnrepository.com/artifact/log4j/log4j/1.2.17
testng
        <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.properties
register.Url=http://8080/lmcanon_web_auto/mng/register.html
login.Url=http://8080/lmcanon_web_auto/mng/login.html

2,测试方法
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,sendKeys
logger.info("输入数据:"+value);
2,getText
logger.info("获取元素本文内容,值为:"+text);
3,click
logger.info("触发点击事件");

-- 封装日志
为了方便元素操作记录日志,可以封装元素的操作方法,在方法内做日志
就能达到统一做日志的效果,一劳永逸
做法:
采取在findelement/findElements方法内做日志
做法
对整个unitl方法做捕捉处理,记录日志信息。
初始化日志内容
String tips=
"获取元素列表:{'by','"+locator.getBy()+"'},{'value','"+locator.getValue()+"'}");
成功情况:tips拼接【成功】
错误情况:tips拼接【失败】

--72检查点
设计断言类Assertion,处理多种场景断言
1,assertTextPresent:断言期望值出现在了页面
2,assertTextNotPresent
3,assertTextPresentPrecesion断言期望值与实际值一致
4,assertTextNotPresentPrecesion
5,assertElementEditable断言期望值是否可编辑
6,assertElementNotEditable
7,assertElementAttributeValueEquals
8,assertElementAttributeValueNotEquals
9,assertAlertTextContains
10,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.html
testng自带的报表不够酷炫美观,我们可以集成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.html
reportng生成测试报告位置file:///E:/workspace_java_term2/phoenix_web/target/surefire-reports/html/index.html
-- 74
下载apach
以管理员身份打开命令提示符
CD命令
E:apache2.2in
httpd.exe -k start
E:workspace_java_term1firefoxDemo argetsurefire-reports
E:/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 Info
screenshot=Screen Shot
duratain=Duration
5.修改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_web
2.集成testng:添加基本依赖,testng,selenium,poi-ooxml,dom4j
3.配置xml文件:testng.xml
4.添加一个base父类,
5.根据需求编写测试用例excel文件:register.xlsx
6.写一个工具类用于解析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.53
1.jenkins.war放在apache-tomcat-6.0.53webapps文件夹下面
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方法中加了发送邮件的方法
邮件内容,测试报表的访问路径+日志+测试用例附件

持续集成jenkins
1.jenkins环境搭建(部署war包到tomcat,在war包目录底下执行java-jar jenkins.war)
2.安装默认推荐的插件
3.修改用户登录密码
4.通过全局配置设置了
5.新建任务
6.配置任务:集成svn,修改build信息,设置触发器实现定时构建

原文地址:https://www.cnblogs.com/AIME/p/8872355.html