1、失败实现截图
- 首先把之前写过的截图的方法放入testNGListener里面,由于要用到driver,所以,先去从父类引用下来的onTestFailure(ITestResult tr)这个里面的tr去选择,
- 用tr.getInstance得到的是一个对象
- 所以要把它强转为之前的对象名称
- 然后通过对象去拿到driver
- 最终实现错误截图
代码如下
@Override
public void onTestFailure(ITestResult tr) {
super.onTestFailure(tr);
OneTestCase tc = (OneTestCase) tr.getInstance();
WebDriver driver = tc.driver;
this.takeScreenShot(driver);
}
/**
* 实现截图
* 1、图片的名字 2、图片存的路径(当前类名+当前时间+png)
*/
public void takeScreenShot(WebDriver driver) {
2、log4j环境搭建
- 引入maven的dependency
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- log4j.properties
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://IDEA_WorkSpace//test8//log/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} - [ %5p ] %l %t %c %m %n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = E://IDEA_WorkSpace//test8//log/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} - [ %5p ] %l %t %c %m %n
3、开启邮箱发送
- 首先要获得163的授权码
链接:https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac2cda80145a1742516
/**
* 发送邮件
* 1、用什么邮箱发送 2、登录邮箱 3、谁发给谁 4、标题 5、内容 6、"RVFJQUVMUllWWFZaUExCRg=="
*/
public void sendEmail(){
try {
SimpleEmail email = new SimpleEmail();
//用什么邮箱发送
email.setSslSmtpPort("25");
email.setHostName("smtp.163.com");
//登录邮箱
email.setAuthentication("**发送方的163邮箱**","163的授权码");
//从谁发给谁
email.setFrom("**发送方的163邮箱**");
email.addTo("**收信方的邮箱**");
//发送的标题
email.setSubject("selenium subject");
//发送的内容
email.setMsg("this is test");
//发送
email.send();
logger.debug("邮箱发送成功");
} catch (EmailException e) {
e.printStackTrace();
}
}
4、页面元素被挡住
4.1、使用xpath定位
- 结果:有些标题中有多余的空格不能及时的定位到
代码如下
@Test
public void test1() {
List<String> listString = listCourseTitle();
//用xpath去定位课程的信息,不能用getText
for (int i = 0; i < listString.size(); i++) {
String courseTitle = listString.get(i);
WebElement element = this.driver.findElement(By.xpath("//p[@title='" + courseTitle + "']"));
element.click();
this.driver.navigate().back();
driver.findElement(By.className("js-close")).click();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("第1个case");
}
4.2 使用WebElement定位
@Test
public void test02() {
//获取所有课程的element
List<WebElement> courseList = driver.findElements(By.className("shizan-name"));
//点击下一页循环
List<Integer> numList = pageNumList();
for (int j = 0; j < numList.size() - 1; j++) {
//通过普通for循环去解决
for (int i = 0; i < courseList.size(); i++) {
courseList.get(i).click();
driver.navigate().back();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.findElement(By.className("js-close")).click();
//重新定义courseList
courseList = driver.findElements(By.className("shizan-name"));
}
}
}
/**
* 获取所有的课程标题
*/
public List<String> listCourseTitle() {
List<WebElement> courseList = driver.findElements(By.className("shizan-name"));
List<String> courseXpath = new ArrayList<>();
for (int i = 0; i < courseList.size(); i++) {
courseXpath.add(courseList.get(i).getText());
}
return courseXpath;
}
/**
* 定位页码
*/
public List<Integer> pageNumList() {
ArrayList<Integer> pageNumbers = new ArrayList<>();
List<WebElement> aListElements = driver.findElement(By.className("page")).findElements(By.tagName("a"));
for (WebElement alist : aListElements) {
String pageNum = alist.getText();
if (isNumber(pageNum)) {
int pageNumber = Integer.parseInt(pageNum);
pageNumbers.add(pageNumber);
}
}
return pageNumbers;
}
/**
* 判断是否是数字
*/
public Boolean isNumber(String pageNum) {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNum = pattern.matcher(pageNum);
return isNum.matches();
}
5、PageObject
三个核心项
- 按照页面进行所有元素的封装
- 按照页面对所有的元素的操作进行封装
- 按照页面对所有的case进行封装
6、pageobject 实现代码(部分)
6.1、page层
BasePage页面
package com.hws.page;
import com.hws.web.OneTestCase;
import com.hws.web.util.ProUtil;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
/**
* ClassName:BasePage
* Package:com.hws.page
* Description:
*
* @ date:2020/3/29 19:11
* @ author:hws
*/
public class BasePage {
public WebDriver driver;
static Logger logger = Logger.getLogger(BasePage.class);
public BasePage(WebDriver driver) {
this.driver = driver;
}
/**
* 对获取的方式进行封装(重构)
*/
public By getByLocal(String key) {
ProUtil proUtil = new ProUtil("element.properties");
logger.debug("你的定位信息是" + key);
//下面的getPro(key)得到的是这一串name>email,用split给它分隔开
String locator = proUtil.getPro(key);
String locatorBy = locator.split(">")[0];
String locatorValue = locator.split(">")[1];
logger.debug("你的定位方式是" + locatorBy);
logger.debug("你的定位值是" + locatorValue);
if ("id".equals(locatorBy)) {
return By.id(locatorValue);
} else if ("className".equals(locatorBy)) {
return By.className(locatorValue);
} else if ("name".equals(locatorBy)) {
return By.name(locatorValue);
}
return By.xpath(locatorValue);
}
/**
* 对driver进行封装,并将ProUtil工具类引入
*/
public WebElement getElement(String key) {
return driver.findElement(this.getByLocal(key));
}
/**
* 鼠标移动element
*/
public void moveToElement(WebElement toElement) {
Actions actions = new Actions(driver);
actions.moveToElement(toElement).perform();
}
}
LoginPage.java
package com.hws.page;
import com.hws.web.OneTestCase;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.BeforeClass;
import java.util.Collections;
/**
* ClassName:LoginPage
* Package:com.hws.page
* Description:
*
* @ date:2020/3/28 21:25
* @ author:hws
*/
public class LoginPage extends BasePage {
public WebDriver driver;
public LoginPage(WebDriver driver) {
super(driver);
}
public WebElement loginTextElement(){
//首页右上角的登录,在handle要点击
return getElement("logintext");
}
public WebElement emailElement(){
//登录界面账户框
return getElement("username");
}
public WebElement passwordElement(){
//登录界面的密码框
return getElement("password");
}
public WebElement loginElement(){
//登录界面的登录按钮
return getElement("loginbtn");
}
public WebElement autoSignInElement(){
//七天自动登录选框
return getElement("autosignin");
}
public WebElement getUserPngElement(){
return getElement("headpng");
}
public WebElement getUserInfoElement(){
return getElement("userinfo");
}
public void closeWeb(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
}
6.2 Handle层
package com.hws.handle;
import com.hws.page.LoginPage;
import com.hws.web.OneTestCase;
import org.apache.log4j.Logger;
import org.openqa.selenium.WebDriver;
/**
* ClassName:LoginHandle
* Package:com.hws.handle
* Description:
*
* @ date:2020/3/29 19:45
* @ author:hws
*/
public class LoginHandle {
public LoginPage loginPage;
static Logger logger = Logger.getLogger(LoginHandle.class);
public LoginHandle(WebDriver driver) {
loginPage = new LoginPage(driver);
}
public void clickLoginText() {
loginPage.loginTextElement().click();
}
public void sendEmail(String email) {
logger.debug("你输入的邮箱是" + email);
loginPage.emailElement().sendKeys(email);
}
public void sendPassword(String password) {
logger.debug("你输入的密码是" + password);
loginPage.passwordElement().sendKeys(password);
}
public void clickAutoSignIn() {
loginPage.autoSignInElement().click();
}
public void clickLoginBtn() {
logger.debug("点击登录按钮--->");
loginPage.loginElement().click();
}
public void waitTimes(Integer time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getUserText() {
loginPage.moveToElement(loginPage.getUserPngElement());
this.waitTimes(200);
return loginPage.getUserInfoElement().getText();
}
}
6.3 runcase层
package com.hws.runcase;
import com.hws.handle.LoginHandle;
import com.hws.web.OneTestCase;
import com.hws.web.TestNGListenerScreen;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import java.util.Collections;
/**
* ClassName:LoginCase
* Package:com.hws.runcase
* Description:
*
* @ date:2020/3/29 20:10
* @ author:hws
*/
@Listeners({TestNGListenerScreen.class})
public class LoginCase {
Logger logger = Logger.getLogger(LoginCase.class);
public LoginHandle loginHandle;
public WebDriver driver;
/**
* 初始化驱动Driver
*/
@BeforeClass
public void initDriver() {
PropertyConfigurator.configure("log4j.properties");
logger.debug("初始化浏览器");
System.setProperty("webdriver.chrome.driver", "E:\\chromedriver\\chromedriver_win32_2\\chromedriver.exe");
ChromeOptions option = new ChromeOptions();
//通过ChromeOptions的setExperimentalOption方法,传下面两个参数来禁止掉谷歌受自动化控制的信息栏
option.setExperimentalOption("useAutomationExtension", false);
option.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));
driver = new ChromeDriver(option);
driver.manage().window().maximize();
logger.debug("打开浏览器");
driver.get("https://www.imooc.com/");
loginHandle = new LoginHandle(driver);
loginHandle.clickLoginText();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Test
public void testLoginBySuccess(){
logger.debug("开始执行第一个case");
loginHandle.sendEmail("***自己的账户***");
loginHandle.sendPassword("***自己的密码***");
loginHandle.clickAutoSignIn();
loginHandle.clickLoginBtn();
loginHandle.waitTimes(1000);
String username = loginHandle.getUserText();
Assert.assertEquals(username,"***自己的用户名***");
}
@AfterClass
public void AfterClass() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
}
7、testNG数据的传递
异常:
org.testng.TestNGException:
Parameter ‘url’ is required by BeforeClass on method initDriver but has not been marked @Optional or defined
解决:
可以看这个链接 http://www.voidcn.com/article/p-aoxjovoc-btg.html
https://www.cnblogs.com/tobecrazy/p/4590442.html
8、购物流程
8、登录状态检测
通过cookie里面的apsid来进行判断
package com.hws.handle;
import com.hws.runcase.LoginCase;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.Assert;
import org.testng.annotations.*;
import java.util.Collections;
import java.util.Set;
/**
* ClassName:HandleCookie
* Package:com.hws.handle
* Description:
*
* @ date:2020/4/1 10:17
* @ author:hws
*/
public class HandleCookie {
public LoginHandle loginHandle;
public WebDriver driver;
/**
* 初始化驱动Driver
*/
@BeforeClass
public void initDriver() {
PropertyConfigurator.configure("log4j.properties");
System.setProperty("webdriver.chrome.driver", "E:\\chromedriver\\chromedriver_win32_2\\chromedriver.exe");
ChromeOptions option = new ChromeOptions();
//通过ChromeOptions的setExperimentalOption方法,传下面两个参数来禁止掉谷歌受自动化控制的信息栏
option.setExperimentalOption("useAutomationExtension", false);
option.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));
driver = new ChromeDriver(option);
driver.manage().window().maximize();
}
@BeforeMethod
public void beforeMethod() {
driver.get("https://coding.imooc.com/class/427.html");
loginHandle = new LoginHandle(driver);
Set<Cookie> cookies = driver.manage().getCookies();
for (Cookie cookie:cookies){
System.out.println("Before--->"+cookie);
}
loginHandle.clickLoginText();
loginHandle.waitTimes(1500);
}
@Test
public void testCookie() {
loginHandle.sendEmail(loginHandle.getUserName("user0"));
loginHandle.sendPassword(loginHandle.getPassword("user0"));
loginHandle.clickAutoSignIn();
loginHandle.clickLoginBtn();
loginHandle.waitTimes(2000);
Set<Cookie> cookies = driver.manage().getCookies();
for (Cookie cookie:cookies){
if (cookie.getName().equals("apsid")){
System.out.println("获取cookie成功,登录成功");
}
}
}
@AfterMethod
public void afterMethod() {
}
@AfterClass
public void AfterClass() {
/* try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();*/
}
}
9、用cookie方式注入
@BeforeMethod
public void beforeMethod() {
driver.get("https://coding.imooc.com/class/427.html");
loginHandle = new LoginHandle(driver);
Set<Cookie> cookies = driver.manage().getCookies();
for (Cookie cookie : cookies) {
System.out.println("Before--->" + cookie);
}
loginHandle.waitTimes(2000);
}
@Test
public void testCookie() {
String value = "hiMDc5NGNjZDU2N2Y0ZTIzMTg2YTA1ZjY4ZjA2NzkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANTg2MjcxNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMjExNTg4NjE2QHFxLmNvbQAAAAAAAAAAAAAAAAAAADFmM2E5YjZlY2E5ZjlkYjY2M2IyNzI5ZDAyY2VmMDBmRTqEXkU6hF4%3DMz";
Set<Cookie> cookies = driver.manage().getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equals("apsid")) {
System.out.println("获取cookie成功,登录成功");
}
}
Cookie cookie = new Cookie("apsid", value, ".imooc.com", "/", null);
driver.manage().addCookie(cookie);
driver.navigate().refresh();
loginHandle.waitTimes(2000);
Set<Cookie> cookies2 = driver.manage().getCookies();
for (Cookie cookie1 : cookies2) {
System.out.println("After-->" + cookie1);
}
}
10、Cookie登录并加入购物车
package com.hws.runcase;
import com.hws.handle.CourseHandle;
import com.hws.handle.LoginHandle;
import com.hws.web.TestNGListenerScreen;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.Assert;
import org.testng.annotations.*;
import java.util.Collections;
/**
* ClassName:CourseCase
* Package:com.hws.runcase
* Description:
*
* @ date:2020/4/1 17:47
* @ author:hws
*/
@Listeners({TestNGListenerScreen.class})
public class CourseCase {
Logger logger = Logger.getLogger(CourseCase.class);
public CourseHandle courseHandle;
public WebDriver driver;
/**
* 初始化驱动Driver
*/
@BeforeClass
public void initDriver() {
PropertyConfigurator.configure("log4j.properties");
System.setProperty("webdriver.chrome.driver", "E:\\chromedriver\\chromedriver_win32_2\\chromedriver.exe");
ChromeOptions option = new ChromeOptions();
//通过ChromeOptions的setExperimentalOption方法,传下面两个参数来禁止掉谷歌受自动化控制的信息栏
option.setExperimentalOption("useAutomationExtension", false);
option.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));
driver = new ChromeDriver(option);
driver.manage().window().maximize();
}
@BeforeMethod
public void beforeMethod() {
driver.get("https://coding.imooc.com/class/427.html");
courseHandle = new CourseHandle(driver);
courseHandle.waitTimes(1500);
}
@Test
public void testAddCourseSuccess() {
int number = 0;
boolean flag = courseHandle.isTrueTitle("专为程序员设计的高等数学课");
logger.debug("flag=" + flag);
Assert.assertTrue(flag);
courseHandle.addUserCookie();
driver.navigate().refresh();
courseHandle.waitTimes(500);
int beforeCartNumber = courseHandle.getCartNumber();
courseHandle.clickAddShop();
courseHandle.waitTimes(1000);
int afterCartNumber = courseHandle.getCartNumber();
if(courseHandle.isEnableAlready()){
courseHandle.closeAlreadyBtn();
Assert.assertEquals(number,0);
}else {
number = afterCartNumber - beforeCartNumber;
Assert.assertEquals(number,1);
}
}
@AfterMethod
public void afterMethod() {
}
@AfterClass
public void AfterClass() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
}
testng.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite">
<listeners>
<listener class-name="org.uncommons.reportng.HTMLReporter"/>
<listener class-name="org.uncommons.reportng.JUnitXMLReporter"/>
<listener class-name="com.hws.util.TestCaseReport"/>
</listeners>
<test verbose="2" preserve-order="true" name="E:/IDEA_WorkSpace/test8">
<classes>
<class name="com.hws.runcase.CourseCase">
<methods>
<include name="testAddCourseSuccess"/>
</methods>
</class>
</classes>
</test>
</suite>
11、在多个浏览器上面运行
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite" parallel="true" thread-count="2">
12、订单流程封装
定位元素信息报空指针异常的时候,看看你的driver有没有初始化。
可以看看这个文章解决 http://www.cocoachina.com/cms/wap.php?action=article&id=79410