1、元素是否唯一
2、List定位和层级定位
3、CSS ID选择器查找元素
注意
- 如果元素的ID不唯一,或者是动态的
- 或者name和linketext的属性值也不唯一
- 就要考虑用xpath来查找元素,然后再对元素执行操作
4、十大定位方式
可以参考这个,写的十分好
https://www.cnblogs.com/qingchunjun/p/4208159.html
- By.id
- By.name
- By.tagName
- By.className
- By.linkText
- By.partialLinkText
- By.xpath
- By.cssSeletor
- List定位
- 层级定位
5、单选框测试
源码如下:
public class SeleniumAction {
public WebDriver driver;
/**
* 初始化驱动Driver
*/
public void initDriver() {
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();
driver.get("https://www.imooc.com/user/setprofile");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 登录页面的input
*/
public void inputElement() {
//输入手机号或邮箱
WebElement emailElement = driver.findElement(By.name("email"));
//拿到placeholder里的值
String userInfo = emailElement.getAttribute("placeholder");
System.out.println(userInfo);
//设置手机号
emailElement.sendKeys("15088******");
//设置登录密码
driver.findElement(By.name("password")).sendKeys("********");
//点击登录并进行跳转
driver.findElement(By.className("moco-btn-red")).click();
//让线程等1.5秒钟
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 个人信息界面修改
*/
public void radio() {
driver.get("https://www.imooc.com/user/setprofile");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.findElement(By.linkText("编辑")).click();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//父节点
WebElement userFrom = driver.findElement(By.id("profile"));
//子节点
List<WebElement> sexList = userFrom.findElements(By.name("sex"));
//通过isSeleceted可以判断元素是否被选中
for (WebElement sex : sexList) {
if(sex.isSelected()){
break;
}else {
sex.click();
}
}
//获取第三个女的按钮
sexList.get(2).click();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SeleniumAction seleniumAction = new SeleniumAction();
seleniumAction.initDriver();
seleniumAction.inputElement();
seleniumAction.radio();
}
}
6、多选框测试
/**
* 多选框
*/
public void checkBox(){
WebElement box = driver.findElement(By.className("auto-cbx"));
System.out.println(box.isSelected());
System.out.println(box.isEnabled());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
box.click();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
public static void main(String[] args) {
SeleniumAction seleniumAction = new SeleniumAction();
seleniumAction.initDriver();
seleniumAction.checkBox();
}
7、button按钮
document.getElementsByClassName("moco-btn-red")[0].style.display="none";
执行此段代码前:
执行此段代码后:
/**
* 登录按钮
*/
public void button() {
WebElement loginBtn = driver.findElement(By.className("moco-btn-red"));
System.out.println(loginBtn.isDisplayed());
System.out.println(loginBtn.isEnabled());
System.out.println("-------------");
String jsString = "document.getElementsByClassName('moco-btn-red')[0].style.display='none'";
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript(jsString);
WebElement loginBtn1 = driver.findElement(By.className("moco-btn-red"));
System.out.println(loginBtn1.isDisplayed());
System.out.println(loginBtn1.isEnabled());
System.out.println("-------------");
}
执行结果:
true
true
-------------
false
true
-------------
8、文件的上传(针对input类型的)
这里有2个坑,我使用的是模拟鼠标点击
Ⅰ、用的是Actions,而不是Action,Actions是位于Selenium里面的
Ⅱ、actions执行完moveToElement的时候,一定要进行perform进行提交,否则后面元素查找的时候会出现元素不可交互的错误
Message: element not interactable
/**
* 文件上传(input类型)
*/
public void upFile(){
driver.get("https://www.imooc.com/user/setprofile");
//定位更换头像的元素
WebElement headImg = driver.findElement(By.className("avator-mode"));
//模拟鼠标移动,用Actions的形式,引入的是Selenium里面的
Actions actions = new Actions(driver);
//这里一定要给它perform提交
actions.moveToElement(headImg).perform();
//定位鼠标移动过后的更换头像
WebElement changeImg = driver.findElement(By.className("js-avator-link"));
changeImg.click();
//放入照片
driver.findElement(By.id("upload")).sendKeys("E:\\1\\3.jpg");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
9、文件上传,均可以用(用模拟键盘来实现的)
/**
* 文件上传(通过模拟键盘的ctrl+v+enter进行)
*/
public void upFileByKey(){
driver.get("https://www.imooc.com/user/setprofile");
//定位到更新头像的元素
WebElement updateImg = driver.findElement(By.className("avator-mode"));
//用Actions模拟点击,并通过perform提交
Actions actions = new Actions(driver);
actions.moveToElement(updateImg).perform();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//鼠标点击要更换头像
driver.findElement(By.className("js-avator-link")).click();
//鼠标点击上传头像
driver.findElement(By.className("avator-btn-fake")).click();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//使用Ctrl+v+enter进行操作
//1、选择图片的地址
StringSelection selectJpg = new StringSelection("E:\\1\\3.jpg");
Clipboard sysc = Toolkit.getDefaultToolkit().getSystemClipboard();
sysc.setContents(selectJpg,null);
//2、使用Robot进行Ctrl+v+enter操作
try {
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_CONTROL);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (AWTException e) {
e.printStackTrace();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
10、下拉框的选中显示
/**
* 下拉列表显示
*/
public void selectOption(){
driver.get("https://www.imooc.com/user/setprofile");
driver.findElement(By.className("js-edit-info")).click();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
WebElement userForm = driver.findElement(By.id("profile"));
userForm.findElement(By.id("job")).click();
//这里是用userFrom去查询,不能通过driver去查询,否则数据重复性会很多
List<WebElement> jobList = userForm.findElements(By.tagName("option"));
//点击职位名称
jobList.get(6).click();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
11、下拉框选中显示,使用自带的Select方法
11.1、下拉框操作
- 选择对应的元素
- 不选择对应的元素
- 获取选择项的值
11.2、实现的代码
/**
* 下拉框显示(通过Selenium自带的Select方法进行选择,不通过自己进行封装)
*/
public void selectOptionSelenium(){
driver.get("https://www.imooc.com/user/setprofile");
//点击编辑按钮
driver.findElement(By.className("js-edit-info")).click();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//定位弹弹框中的职位
WebElement userFrom = driver.findElement(By.id("profile"));
WebElement jobList = userFrom.findElement(By.name("job"));
//用Selenium自带的select进行处理
Select select = new Select(jobList);
//通过index的形式
//select.selectByIndex(6);
//通过value的形式
select.selectByValue("11");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
select.selectByVisibleText("产品经理");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
12、元素进阶(Actions,鼠标事件)
- 鼠标左击
Actions actions = new Actions(driver);
//鼠标左击
actions.click().perform();
- 鼠标右击
Actions actions = new Actions(driver);
//鼠标右击
actions.contextClick().perform();
- 鼠标悬停
Actions actions = new Actions(driver);
//鼠标悬停
actions.moveToElement(jobList).perform();
实现的代码
/**
* 模拟鼠标移动
*/
public void moseAction(){
driver.get("https://www.imooc.com/");
//用层级定位,定位出大的div,再定位小的div
WebElement menuContent = driver.findElement(By.className("menuContent"));
//找到大的div后,还会出现很多items,还是得用findElements来进行
List<WebElement> items = menuContent.findElements(By.className("item"));
//选择第二个,也就是索引是1的WebElement
WebElement mobileElement = items.get(1);
//模拟鼠标悬停,用Actions,最后再perform提交
Actions actions = new Actions(driver);
actions.moveToElement(mobileElement).perform();
driver.findElement(By.linkText("小程序")).click();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
13、窗体分类
- iframe
使用switchTo() - 弹窗
使用switchTo()和getWindowHandles()来处理 - 浏览器多窗口
13.1、iframe实践
/**
* iframe进行操作,一些内嵌页面上面可能会有
*/
public void switchIframe(){
driver.get("https://www.imooc.com/article/publish#");
WebElement iframeElement = driver.findElement(By.id("ueditor_0"));
driver.switchTo().frame(iframeElement);
WebElement editor = driver.findElement(By.tagName("p"));
Actions moueseActions = new Actions(driver);
moueseActions.moveToElement(editor).click().sendKeys("This is text").perform();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
13.2 浏览器多窗口
/**
* 多窗口的切换
*/
public void windowsHandle(){
driver.get("https://coding.imooc.com/?c=miniprogram");
//拿到所有的窗口
Set<String> windowHandles = driver.getWindowHandles();
//拿到当前的窗口
String currentWindow = driver.getWindowHandle();
//遍历所有的窗口,和当前的窗口进行对比
for(String s : windowHandles){
if(s.equals(currentWindow)){
continue;
}else {
//切换到window当前的页面
driver.switchTo().window(s);
}
}
driver.findElements(By.className("shizhan-course-wrap")).get(1).click();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
13.3 浏览器多个弹窗
/**
* 弹窗的操作
*/
public void alertWindows(){
driver.get("********弹窗的网址********");
//第一个就是普通的弹窗
driver.findElement(By.id("firstAlert")).click();
//网页弹出消息显示和确认按钮,通过switchTo里面的alert弹窗,然后选择accept也就是接受
driver.switchTo().alert().accept();
//第二个弹框的话,消息加一个取消和确认的按钮,点击确定或取消的话,进入对应的页面,这里要进行页面刷新
driver.findElement(By.id("secondAlert")).click();
//取消就是dismiss,确认就是accept
driver.switchTo().alert().dismiss();
//页面刷新
driver.navigate().refresh();
//第三个弹框的话,是里面要输入一些文字,然后进行对应的页面
driver.findElement(By.className("thirdAlert")).click();
driver.switchTo().alert().sendKeys("hello hws");
//页面刷新
driver.navigate().refresh();
driver.close();
}
14、3种不同形式的等待
- 强制等待:Thread.sleep
- 显示等待:不用等太长时间
- 隐式等待:全局进行等待
也可以看这个链接
https://blog.csdn.net/woshiweiweily/article/details/103408847
代码如下:
/**
* 3种不同形式的等待
*/
public void waitWeb(){
//1、强制等待,强制等待0.5秒后,进行下一步操作;缺点:不能准确把握需要等待的时间
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//2、显示等待,判断准确,不会浪费多余的等待时间;缺点:使用相对比较复杂
WebDriverWait webDriverWait = new WebDriverWait(driver, 10);
webDriverWait.until(ExpectedConditions.presenceOfElementLocated(By.id("needID")));
//3、隐式等待,优点:隐式等待对整个driver的周期都起作用;缺点:不是很灵活
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
15、Selenium工作原理
比较常用css或者xpath定位(适合Web)
16、登录的需求
- 逻辑分析
17、IDEA 内的Selenium配置
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.14.0</version>
</dependency>
<!-- 与 selenium-java 版本要一致 -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-api</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
18、重构登录脚本
/**
* 实现登录
*/
public void userLogin() {
String userGetBy = "name";
String userElement = "email";
String userName = "********";
String pwdGetBy = "name";
String pwdElement = "password";
String password = "************";
String loginGetBy = "className";
String loginElement = "moco-btn-red";
driver.findElement(By.id("js-signin-btn")).click();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.findElement(this.getByLocal(userGetBy,userElement)).sendKeys(userName);
driver.findElement(this.getByLocal(pwdGetBy,pwdElement)).sendKeys(password);
driver.findElement(this.getByLocal(loginGetBy,loginElement)).click();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//校验
WebElement headPng = driver.findElement(By.id("header-avator"));
Actions actions = new Actions(driver);
actions.moveToElement(headPng).perform();
String text = driver.findElement(By.className("text-ellipsis")).getText();
try {
if ("*****userName****".equals(text)) {
System.out.println("登录成功");
} else {
System.out.println("登录信息不匹配" + text);
}
}catch (Exception e){
System.out.println("登录失败");
}
}
/**
* 对获取的方式进行封装(重构)
*/
public By getByLocal(String getBy, String getValue) {
if ("id".equals(getBy)) {
return By.id(getValue);
} else if ("className".equals(getBy)) {
return By.className(getValue);
} else if ("name".equals(getBy)) {
return By.name(getValue);
}
return By.xpath(getValue);
}
19、读取配置文件
用properties来读取
- load
- setProperties
- getProperties
实现代码
public class ProUtil {
public static void main(String[] args) {
Properties properties = new Properties();
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("element.properties");
BufferedInputStream inputStream = new BufferedInputStream(fileInputStream);
try {
properties.load(inputStream);
String username = properties.getProperty("username");
System.out.println(username);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
20、重构读取配置文件
public class ProUtil {
public Properties pro;
public ProUtil(String filePath){
pro = readProperties(filePath);
}
private Properties readProperties(String filePath){
Properties properties = new Properties();
try {
FileInputStream fileInputStream = new FileInputStream(filePath);
BufferedInputStream inputStream = new BufferedInputStream(fileInputStream);
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return properties;
}
private String getPro(String key){
if(pro.containsKey(key)){
String value = pro.getProperty(key);
return value;
}
return "";
}
public static void main(String[] args) {
ProUtil proUtil = new ProUtil("element.properties");
String username = proUtil.getPro("username");
System.out.println(username);
}
}
21、testNG
- 安装testNG框架
http://www.mamicode.com/info-detail-2899087.html
https://www.cnblogs.com/54tester/p/11518263.html
https://blog.csdn.net/u010270891/article/details/82978260 - 学习testNG感觉这个写得也还不错
https://www.bbsmax.com/A/B0zqQGeGzv/
http://www.51testing.com/zhuanti/TestNG.htm - IDEA使用
Ⅰ、引入plugin里面的testNG.xml 2020/03/26去idea的plugin里面搜索的时候只有testNG.xml了,就把它引入就可以了
Ⅱ、引入testNG-j插件,下载地址 https://plugins.jetbrains.com/plugin/137-testng-j
Ⅲ、安装testNG依赖,maven那里下载即可
22、testNG执行顺序
beforeTest -> beforeClass -> beforeMethod -> test -> AfterMethod -> AfterClass -> AfterTest
23、testNG 报错
Cannot inject @Test annotated Method [userLogin] with [class java.lang.String].
原因:@Test注解的方法不能带参数
解决方法 :去掉参数后,再执行,就没再报错了。
24、可以选择从user.properties里面找多个用户信息并登录
实现的代码如下:
public class TestCase {
public WebDriver driver;
@BeforeTest
public void beforeTest(){
System.out.println("beforeTest");
}
/**
* 初始化驱动Driver
*/
@BeforeClass
public void initDriver() {
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();
driver.get("https://www.imooc.com/user/newlogin");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 对获取的方式进行封装(重构)
*/
public By getByLocal(String key) {
ProUtil proUtil = new ProUtil("element.properties");
//下面的getPro(key)得到的是这一串name>email,用split给它分隔开
String locator = proUtil.getPro(key);
String locatorBy = locator.split(">")[0];
String locatorValue = locator.split(">")[1];
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) {
WebElement element = driver.findElement(this.getByLocal(key));
return element;
}
/**
* 测试实现登录
*/
@Test
public void userLogin() {
String user = null;
String userName;
String passWord;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//用之前的工具类获取username和password
ProUtil proUtil = new ProUtil("user.properties");
int lines = proUtil.getLines();
for (int i = 0; i < lines; i++) {
user = proUtil.getPro("user" + i);
userName = user.split(">")[0];
passWord = user.split(">")[1];
WebElement usernameElement = getElement("username");
usernameElement.sendKeys(userName);
WebElement passwordElement = getElement("password");
passwordElement.sendKeys(passWord);
getElement("loginbtn").click();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//校验
try {
WebElement headPng = getElement("headpng");
Actions actions = new Actions(driver);
actions.moveToElement(headPng).perform();
String text = getElement("userinfo").getText();
if ("***登录后的用户名***".equals(text)) {
System.out.println("登录成功");
} else {
System.out.println("登录信息不匹配" + text);
}
} catch (Exception e) {
System.out.println("登录失败");
}
//下次执行的时候,这里的输入框要清空
usernameElement.clear();
passwordElement.clear();
}
}
@AfterMethod
public void AfterMethod(){
System.out.println("AfterMethod");
}
@AfterClass
public void AfterClass(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.close();
}
@AfterTest
public void AfterTest(){
System.out.println("AfterTest");
}
}
25、实现截图
- 首先的话,要确定文件的名称和文件放置的路径
- 然后选用Files.copy,用的是common.io里面的,有fileForm和fileTo
实现的代码如下:
实现代码一:
/**
* 实现截图
* 1、图片的名字 2、图片存的路径
*/
public void takeScreenShot(Integer i) {
String screenFilePath = "E:\\IDEA_WorkSpace\\test8\\screenFile\\user(" + i + ")login.png";
File screenFile = ((RemoteWebDriver) driver).getScreenshotAs(OutputType.FILE);
ProUtil proUtil = new ProUtil("user.properties");
//注意,这个的Files用的是import com.google.common.io.Files;这个下面的,也可以看提示,有fileFrom和fileTo
try {
assert screenFilePath != null;
Files.copy(screenFile, new File(screenFilePath));
} catch (IOException e) {
e.printStackTrace();
}
}
实现代码二:
/**
* 实现截图
* 1、图片的名字 2、图片存的路径(当前类名+当前时间+png)
*/
public void takeScreenShot() {
//格式化然后获得当前的时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
String currentTime = sdf.format(new Date());
//获得当前的类名的名字
String currentClass = this.getClass().getName();
//整合成最终图片的名字
String imgPath = currentClass + currentTime + ".png";
//获取存放当前所有图片的文件路径(或者说是这个项目路径下面的某一个文件夹)
String currentPath = "E:\\IDEA_WorkSpace\\test8\\screenFile\\";
String finalImgPath = currentPath + imgPath;
File screenFile = ((RemoteWebDriver) driver).getScreenshotAs(OutputType.FILE);
ProUtil proUtil = new ProUtil("user.properties");
//注意,这个的Files用的是import com.google.common.io.Files;这个下面的,也可以看提示,有fileFrom和fileTo
try {
Files.copy(screenFile, new File(finalImgPath));
} catch (IOException e) {
e.printStackTrace();
}
}
26、testTG实现监听以及代码实现
- 首先建立一个testTG的class的文件,去继承TestListenerAdapter,
- 然后先super父类的onTestFailure,写上要输出的语句
- 最后添加监听@Listener(TestListenerScreen.class)
实现的代码
public class TestNGListenerScreen extends TestListenerAdapter {
@Override
public void onTestFailure(ITestResult var1) {
super.onTestFailure(var1);
System.out.println("第一个case失败执行的");
}
}
@Listeners({TestNGListenerScreen.class})
public class OneTestCase {