Selenium寻找元素定位
id
findElement(by.id(“id”))
name
findElement(by.name(“name”))
class_name
findElement(by.className(“className”))
linkText
driver.findElement(By.linkText("Inbox"));
partialLinkText
driver.findElement(By.partialLinkText("Inbox"));
tagName
tagName(“html的类别信息如button”)
Css
1)绝对路径 在DOM中的具体位置
findElement(by.cssSelector(“html body div form input”))
或findElement(by.cssSelector(“html>body>div>form>input”))
2)相对路径
driver.findElement(By.cssSelector("input"));第一个input元素。
driver.findElement(By.cssSelector("input.login")); html标签.class的属性值
3)相对Id选择器
driver.findElement(By.cssSelector("input#username"));html标签#id
driver.findElement(By.cssSelector("#username"));只是#id
4)属性
driver.findElement(By.cssSelector("input[name=username]"));使用name属性
driver.findElement(By.cssSelector("img[alt='Previous']"));使用alt属性
driver.findElements(By.cssSelector("img[alt]"));通过属性名称查找,页面所有img含 有alt属性的标签
driver.findElement(By.cssSelector("input[type='submit'][value='Login']"));联合多个属 性查询
driver.findElements(By.cssSelector("img:not([alt])"));使用伪类
5)部分属性 (对于页面上有动态变化的属性的元素是非常有用的)
^= driver.findElement(By.cssSelector(Input[id ^ =‘ ctrl’]));匹配到id头部 如ctrl_12
$= driver.findElement(By.cssSelector(Input[id ^ =‘ ctrl’]));匹配到id尾部 如a_ctrl
*= driver.findElement(By.cssSelector(Input[id *=‘ ctrl’]));匹配到id中间如1_ctrl_12
高级CSS
1)查询子元素
WebElement userName = driver.findElement(By.cssSelector("form#loginForm > input"));
WebElement userName = driver.findEleme(By.cssSelector("form#loginForm :nth-child(2)"));
:first-child 定位表单第一个子元素
:last-child 定位表单最后一个子元素
:nth-child(2) 定位表单中第二个子元素
2)使用伪类
driver.findElement(By.cssSelector("input:focus")); 也可使用hover active
:enable input:enable 定位属性为enable的input元素
:disable input:disable 定位属性为disable的input元素
:checked input:checked 定位有多选框属性为checked的元素
3)查询兄弟元素
driver.findElement(By.cssSelector("#nv a + b")); 定位到a 再定位到和它相邻的b
Xpath(可以向前向后查询DOM结构,css只能向前)
1)绝对路径
driver.findElement(By.xpath("html/body/div/div/form/input"));//如果发生结构改变则 找不到
2)相对路径
driver.findElement(By.xpath("//input"));//假设在DOM中的第一个
3)使用索引
driver.findElement(By.xpath("//input[2]"));//找第二个input元素
4)属性值
driver.findElement(By.xpath("//input[@id='username']"));//使用id属性匹配
driver.findElement(By.xpath("img[@alt='Previous']"));//使用alt属性
driver.findElement(By.xpath ("//input[@type='submit'][@value='Login']"));//联合多个属性
WebElement previousButton = driver.findElement (By.xpath("//input[@type='submit'and @value='Login']"));//使用and联合查询
WebElement previousButton = driver.findElement (By.xpath("//input[@type='submit'or @value='Login']"));//使用or选择查询
5)属性名称
List imagesWithAlt = driver.findElements (By.xpath ("img[@alt]"));//使用属 性名称 img中带有alt属性的元素
6)部分属性值
starts-with() driver.findElement(By.XPath(“input[starts-with(@id,’ctrl’)]”));
ends-with() driver.findElement(By.XPath(“input[ends-with(@id,’ctrl’)]”));
contains() starts-with() driver.findElement(By.XPath(“input[contains(@id,’ctrl’)]”));
7)使用值匹配任意元素属性值
driver.findElement(By.xpath("//input[@*='username']"));任意属性名称为username的元素
8)XPath轴 借住于元素与元素之间的关系定位
ancestor //td[text()=’Product1’]/ancestor::table 选择当前节点所有的父类元素
属性 名称 元素
descendant //table/descendant::td/input 选择当前节点所有子元素
following //td[text()=’Product1’]/following::tr 选择当前元素结束标签后的所有元素
following-sibling //td[text()=’Product1’]/following-sibling::td 当前元素后的兄弟元素
preceding //td[text()=’$150’]/preceding::tr 当前节点开始标签之前的所有节点
preceding-sibling //td[text()=’$150’]/preceding-sibling::td 当前借点之前的所有同级节点
定位单元格元素
方式:
table:定义表格
caption:表格标题
th:表头
tr:行
td:单元
thead:页眉
tbody:主题
tfoot:页脚
col:列的属性
colgroup:列的组
findElement将会查询整个DOM 最终返回第一个找到的匹配的元素
findElement可以查询子类,缩写为
driver.findElement(By.id("div1")).findElement(By.linkText("top"));
查找一个元素 查找这个元素下的子类top
当findElement找不到元素时。抛出NoSuchElementFoundException
findElements()方法返回所有匹配定位策略的WebElement的集合,我们可以使用Java中List类来创建WebElements的实例,实现查找多个元素:
List links = driver.findElements(By.cssSelector("#nv a"));
【附录】
1.元素定位
在本章中,我们将讨论
u 使用浏览器工具来检查页面中元素的结构
u 使用findElement方法定位元素
u 使用findElements方法来定位元素
u 定位链接
u 通过标签名称定位元素
u 使用CSS选择器定位元素
u 使用XPath定位元素
u 使用文本定位元素
u 使用高级CSS选择器定位元素
u 使用jQuery选择器
u 定位表格的行和列
u 定位表格中的子元素
1.1.介绍
成功的自动化GUI(图形用户界面)测试取决于从被测试的应用程序中识别和定位GUI元素,然后执行操作和验证这些元素来实现测试流。这可以归结为测试工具有效的识别各种GUI元素的能力。
Selenium WebDriver提供一个先进的技术来定位web页面元素。Selenium功能丰富的API提供了多个定位策略如:Name、ID、CSS选择器、XPath等等。我们也可以执行自定义的定位策略来定位元素。
在本章中,我们将探索如何使用定位策略,从简单的ID,Name和Class开始。
在任何一个Web项目中,给GUI的元素附上属性如Name,ID或Class是非常好的做法。这使得应用程序更加容易测试符合易访问性的标准。但是,有时候并不是所期望的那样。遇到这些场景,我们就需要使用高级的定位策略如CSS选择器和XPath。
CSS选择器和XPath在Selenium用户中非常流行,但是CSS选择器相比XPath从难易、速度、效率来说更为推荐大家使用。
1.2.使用浏览器工具来检查页面元素结构
在我们开始探测定位器之前,我们需要先分析一下页面和元素,了解一下他们的结构,元素有哪些属性,JavaScript或AJAX是怎么调用的。等等。
浏览器为最终用户渲染的视觉元素通过隐藏掉HTML代码和其他资源。当我们想要用Selenium WebDriver自动的进行交互的时候,我们需要仔细查浏览器背后渲染页面和元素的代码。我们需要识别出有用的信息如属性值和元素结构来定位元素,再利用Selenium WebDriver API模拟执行用户的操作。
这里有一个BMI体重计算的页面和HTML代码,下图所示
你可以通过右击浏览器窗口,在弹出的菜单中选择View Page Source来查看页面的代码。代码将会显示在一个独立的窗口中。但这也可能看起来有一点混乱和难以理解。
我们需要一个特别的工具让显示的信息有结构的更易于理解的格式。在这个秘籍中在深入到定位器之前我们将会介绍一些这样的工具。
如何实现如何实现
在下面几个部分中,我们将探讨一些内置在浏览器的工具和插件来分析元素和页面结构。这些工具将帮助我们了解页面上的元素和它们的属性,DOM结构,JavaScript调用,CSS 样式属性等等。
利用Firefox的Firebug插件来检查页面中的元素
新版本的Firefox提供内置的方法来分析页面和元素;然而,我们将使用Firebug插件具有更强大的功能。你需要从 https://addons.mozilla.org/en-us/firefox/addon/ firebug/ 安装Firebug。
检查页面的元素,将鼠标移向所需查看的元素后右键鼠标打开弹出菜单。选择Inspect Element with Firebug选项,如下图所示:
HTML代码在Firebug下以树型结构显示出来,如下图所示:
Firebug提供了各种其他调试特性。它还可以为指定元素生成XPath和CSS选择器。为此,选择所需的元素,然后右击鼠标,选择Copy XPath或Copy CSS Path选项,如下图所示
XPath或CSS选择器的值将会复制剪贴板上。
利用Chrome检查页面中的元素
Chrome提供了一个内置的功能来分析页面和元素。这和firebug很相似。你可以将鼠标移向所需查看的元素,右击弹出菜单,然后选择Inspect Element选项。这将在浏览器中打开开发人员工具。显示信息类似于Firebug,如下图所示:
Chrome开发工具还提供一个特性,在那里你可以得到一个元素的XPath,右键单击所需的元素,从弹出菜单中选择Copy XPath。
利用Internet Explorer检查页面中的元素
类似于Google Chrome,Microsoft Internet Explorer也提供了一个内置的分析页面和元素的特性。
按F12键打开开发人员工具,如下图所示
检查一个元素,单击指针()图标,将鼠标悬停在所需查看的元素上。开发工具高亮此元素为蓝色,HTML代码将以树型结构显示,如下图所示:
如何实现如何实现
浏览器开发工具在测试开发的过程当中派的上用场。这些工具将帮助你找到定位元素,解析代码,以树结构显示出来。这些工具还提供了样式的应用、页面资源,页面的DOM(文档对象模型),JavaScript代码信息等等。
有些工具还可以运行JavaScript代码进行测试和调试。
在下面的秘籍中我们将探索Selenium WebDriver的各种定位器 ,这些工具都将帮助你找到和决定使用哪种Selenium WebDriver API的定位策略和方法。
1.3.使用findElement方法定位元素
selenium WebDriver定位元素是通过使用findElement()和findElements()方法。
findElement()方法返回一个基于指定查寻条件的WebElement对象或是抛出一个没有找到符合条件元素的异常。
findElements()方法会返回匹配指定查询条件的WebElements的集合,如果没有找到则返回为空。
查询方法会将By实例作为参数传入。Selenium WebDriver提供了By类来支持各种查询策略。
下面的表格列出了各种Selenium WebDriver支持的定位策略。
策略
语法
描述
By ID
Java:
driver.findElement(By.id())
通过元素ID属性定位元素
C#: driver.FindElement(By.Id())
Python:
driver.find_element_by_id()
Ruby:
driver.find_element(:id,)
By Name
Java:
driver.findElement(By.name())
通过元素Name属性定位元素
C#:
driver.FindElement(By.Name())
Python:
driver.find_element_by_name()
Ruby:
driver.find_element(:name,)
By class name
Java:driver.findElement(By.className())
通过元素class name属性定位元素
C#:
driver.FindElement(By.ClassName())
Python: driver.find_element_by_class_name()
Ruby:
driver.find_element(:class,)
By tag name
Java: driver.findElement(By.tagName())
通过HTML标记名定位元素
C#: driver.FindElement(By.TagName())
Python: driver.find_element_by_tag_name()
Ruby:
driver.find_element(:tag_name,
By link text
Java:
driver.findElement(By.linkText())
通过文本定位链接
C#:
driver.FindElement(By.LinkText())
Python:
driver.find_element_by_link_text()
Ruby:
driver.find_element(:link_text,< linktext >)
By partial link text
Java:
driver.findElement(By.partialLinkText())
通过部分文本定位链接
C#:
driver.FindElement(By.PartialLinkText())
Python:
driver.find_element_by_partial_link_text()
Ruby:
driver.find_element(:partial_link_text,)
By CSS
Java:
driver.findElement(By.cssSelector())
通过CSS定位元素
C#:
driver.FindElement(By.CssSelector())
Python:
driver.find_elements_by_css_selector ()
Ruby:
driver.find_element(:css,< css selector >)
By XPath
Java:
driver.findElement(By.xpath())
通过XPath定位元素
C#:
driver.FindElement(By.XPath())
Python:
driver.find_elements_by_xpath ()
Ruby:
driver.find_element(:xpath,)
在这个秘籍中,我们将使用findElement()方法来定位元素。
如何实现如何实现
使用id,name或class属性是定位元素的首选方法。让我们试试用上面描述的这些方法来定位元素
通过ID属性来查找元素
用元素的id是最首选的方法来定位页面元素。W3C的标准中推荐开发人员为每一个元素都提供一个独一无二的id属性。拥有id属性,就可以提供一个明确可靠的方法来定位页面上的元素。
当处理DOM的时候,浏览器使用id作为首选识别元素的方法,同时这也是最快速的策略。
现在我们看看如何在一个登录表单中使用id属性来定位元素。
为定位User Name和Password字段,我们可以通过下面方法使用id属性来定位元素:
WebElement username = driver.findElement(By.id("username"));
WebElement password = driver.findElement(By.id("password"));
通过Name属性来查找元素
使用元素的id属性来定位是最为推荐的方法,但是你也可能会因为下列原因不能使用id属性:
l 不是所有的页面上元素都会指定id属性
l id属性的值是动态生成的
在下面的例子中,登录表单使用了name属性而不是id属性
我们可以使用通过下面的方法使用name属性来定位元素:
WebElement username = driver.findElement(By.name("username"));
WebElement password = driver.findElement(By.name("password"));
和id不同,name属性未必是页面上唯一的属性。你可能会找到多个具有相同name属性的元素,在这样的情况下,页面上的第一个出现的元素将会被选择,但是个元素未必是你想寻找的,这将会导致测试失败。
通过CSS属性来查找元素
除了使用id和name属性,你还可以使用class属性来定位元素。class属性是用来指定元素所应用的CSS样式。
在这个例子中,表单元素使用了class属性而不是id属性:
我们可以使用通过下面的方法使用class属性来定位元素
WebElement username =
driver.findElement(By.className("username"));
WebElement password =
driver.findElement(By.className("password"));
如何实现如何实现
Selenium WebDriver 提供了findElement()方法来定位页面中需要测试的元素。
当开始寻找符合指定条件的元素时,它将会查询整个DOM,然后返回第一个找到的匹配的元素。
更多说明 更多说明
WebElement类也可以支持查询子类元素。例如,假设页面上有一些重复的元素。但是,他们在不同的中。我们第一步可以先定位到其父元素
然后在定位其子元素,方法如下:
WebElement div = driver.findElement(By.id("div1"));
WebElement topLink = div.findElement(By.linkText("top"));
你也可以将他们缩写成一行:
WebElement topLink = driver.findElement
(By.id("div1")).findElement(By.linkText("top"));
NoSuchElementFoundException
findElement()和findElements()方法当找不到相应的元素的时候就会抛出NoSuchElementFoundException异常。
1.4.使用findElements方法定位元素
Selenium WebDriver提供了findElements()方法,可以得到匹配指定规则的集合。当我们需要在一组相似的元素上操作的时候,这个方法会是非常有用的。例如,我们可以得到页面上所有的链接或是表格中所有的行等等。
在这个秘籍中,我们将用findElements()方法得到所有的链接并打印他们的目标超链接。
如何实现如何实现
测试需求以百度首页为例,我们要验证百度首页导航链接的数量,并打印出他们的超链接地址
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
@Test
public void test() {
WebDriver driver = new InternetExplorerDriver();
driver.get("http://www.baidu.com");
List
links = driver.findElements(By.cssSelector("#nv a"));
//验证链接数量
assertEquals(10, links.size());
//打印href属性
for (int i = 0; i < links.size(); i++) {
System.out.println(links.get(i).getAttribute("href"));
}
driver.close();
}
}
执行后打印的结果为
http://news.baidu.com/
http://tieba.baidu.com/
http://zhidao.baidu.com/
http://music.baidu.com/
http://image.baidu.com/
http://video.baidu.com/
http://map.baidu.com/
http://baike.baidu.com/
http://wenku.baidu.com/
http://www.baidu.com/more/
findElements()方法返回所有匹配定位策略的WebElement的集合,我们可以使用java中List类来创建WebElements的实例
List类中的size()方法会告诉你这个集合中元素的总数量。
通过for循环将得到List中的所有的元素,再调用getAttribute()方法得到元素的属性。
1.5.定位链接
Selenium WebDriver提供了多种定位链接的方法。你可以通过链接的名称和部分名称来定位一个链接。
当链接名是动态变化的时候,使用部分匹配就变得很方便。在这个秘籍中,我们将看如何使用这些方法来定位页面中的链接。
如何实现如何实现
让我们举个例子来看看如何使用Selenium WebDriver来定位链接。
通过链接名来定位链接
Selenium WebDriver的By类中提供了linkTest()方法来定位链接。在下面的例子中,我们将定位Gmail的链接:
WebElement gmailLink = driver.findElement(By.linkText("GMail"));
assertEquals("http://mail.google.com/",gmailLink.getAttribute("href"));
通过部分链接名称定位链接
Selenium WebDriver的By类也提供了使用部分链接名来定位链接。当开发人员建立了动态的链接名时这种方法就非常的有用。在这个例子中,有一个链接是用来打开收件箱。这个链接同时也会动态的显示收件箱的数量所以他是在动态变化的过程中。这里我们就可以使用partiaLinkTest()来定位固定的或已知不变的一部份名称,在这个例子中就是“inbox”。
WebElement inboxLink =
driver.findElement(By.partialLinkText("Inbox"));
System.out.println(inboxLink.getText());
如果开发人员提供了id,name或是class属性,还是尽量使用这些方法来定位。
1.6.使用标签名称定位元素
Selenium WebDriver的By类中提供了tagName()方法来定位HTML标记名称。这和getElementByTagName()很相似。
使用标签名称可以很方便地定位元素。例如,定位所有的表格中的等等。
在这个秘籍中,我们将学习如何使用tagName来定位元素。
如何实现如何实现
我们假设你的页面中只有一个按钮。你可以使用他的标签来定位此按钮,方法如下:
WebElement loginButton =
driver.findElement(By.tagName("button"));
loginButton.click();
另一个例子如果你想统计中有多少行,你可以这样来做:
WebElement table = driver.findElement(By.id("summaryTable"));
List rows = table.findElements(By.tagName("tr"));
assertEquals(10, rows.size());
tagName方法查询DOM,然后返回所有匹配条件的元素。当定位单独的一个元素时,这种方法是不可靠的,页面上可能有很多相同的元素。
1.7.使用CSS选择器定位元素
Cascading Style Sheets ( CSS )是一种样式风格语言用来描述元素的外观和格式。
主流的浏览器实现CSS解析引擎使用CSS语法来格式化和样式化页面。CSS的引进是为了让页面信息和样式信息可以分开。更多的CSS信息和CSS选择器请访问 http://en.wikipedia.org/wiki/Cascading_Style_Sheets .
Selenium WebDriver使用同样的CSS选择器的原则来定位DOM里的元素。这是一个相对XPath更可靠更快速的方式来定位复杂的元素。
在这个秘籍中,我们将探索一些基本的CSS选择器,后面我们会逐步深入到更高级的用法。
如何实现如何实现
让我们探索一些基本的CSS选择器。Selenium WebDriver的By类提供了cssSelector()方法,让我们可以使用CSS选择器来定位元素。
使用绝对路径来定位元素
CSS绝对路径指的是在DOM结构中具体的位置。下面一个例,使用绝对路径来定位用户名输入字段。在使用绝对路径的时候,每个元素之间要有一个空格。
WebElement userName = driver.findElement(By.cssSelector("html body div div form input"));
你也可以以父子关系的方式”>”来描述这个选择器
WebElement userName = driver.findElement(By.cssSelector("html >
body > div > div > form > input"));
但是,这个策略会有一些的限制,他取决于页面的整个结构。如果有些许改变,选择器将找不到这个元素。
使用相对路径来定位元素
使用相对路径的时候我们可以直接定位元素。不用考虑他在DOM中的位置。例如,我们可以用这样的方法来定位用户输入字段,假设他在DOM中是第一个元素:
WebElement userName = driver.findElement(By.cssSelector("input"));
使用相对路径来定位元素
当我们使用CSS选择器来查找元素的时候,我们可以使用class属性来定位元素。我们可以先指定一个HTML的标签,然后加一个“.”符号,跟上class属性的值,方法如下:
WebElement loginButton =
driver.findElement(By.cssSelector("input.login"));
这同样可以找到按钮的标签class为login的元素。
你还可以简写查询表达示,只用 .和class属性值,省略掉HTML的标签。但是,这将会返回所有class为login的元素,导致结果并不一定是你所期望的那样。
WebElement loginButton = driver.findElement(By.cssSelector(".login"));
此方法和className()很相似。
使用相对ID选择器来定位元素
我们也可以使用元素的ID来定位。先指定一个HTML标签,然后加上一个“#”符号,跟上id的属性值,如下所示:
WebElement userName =
driver.findElement(By.cssSelector("input#username"));
这将会返回input标签中id为username的元素。
你可以通过这样来简化一下表达式,输入“#”符号,跟上id的名称即可,省略到HTML的标签。但是,这也将会返回所有id为username的元素,结果未必是你所期望。用的时候要非常小心。
WebElement userName =
driver.findElement(By.cssSelector("#username"));
这个方法和id选择器策略很像。
使用属性来定位元素
除了class和id属性,CSS选择器也可以使用其他的元素属性来定位。下面的例子中,将使用中的Name属性。
WebElement userName =
driver.findElement(By.cssSelector("input[name=username]"));
使用name属性来定位元素和直接用By类中的name()方法来定位很相似。
让我们试试使用其他的属性,下面的例子中,命名alt属性来定位元素。
WebElement previousButton =
driver.findElement(By.cssSelector("img[alt='Previous']"));
你可以会遇到一个属性不足以来定位到一个元素的情况,你需要联合使用其他的属性来达到精确匹配。下面的例子中,使用多个属性来定位元素。
WebElement previousButton = driver.findElement(By.cssSelector("input[type='submit'][value='Login']"));
使用属性名称选择器来定位元素
这个策略和之前的有些不同,我们只通过指定元素中属性的名称而不是属性的值来定位元素。例如,我们想要查找所有标签中,含有alt属性的元素。
List imagesWithAlt =
driver.findElements(By.cssSelector("img[alt]"));
not()伪类也可以使用来匹配不满足规则的元素。例如,想要定位那些标签中不含有alt属性,方法如下:
List imagesWithoutAlt =
driver.findElements(By.cssSelector("img:not([alt])"));
部分属性值的匹配
CSS选择器提供了一个部分属性值匹配定位元素的方法。这为了测试那些页面上具有动态变化的属性的元素是非常有用的。例如,在ASP.NET应用中,元素id是动态生成的。下面的表格介绍了如何使用部分匹配的语法:
语法
例子
描述
^=
Input[id^= ' ctrl']
以XXX开始 例如,如果一个元素的ID是ctrl_12,就可以定位到此元素,匹配到id的头部ctrl。
$=
input[id$='_userName']
以XXX结尾 例如,如果一个元素的ID是a_1_userName,这将会匹配到id的尾部_userName。
*=
Input[id*='userName']
包含 例如,如果一个元素的ID是panel_
login_userName_textfield,这将会匹配到此id值的_userName,从而定位到元素。
CSS选择器是CSS匹配HTML或XML一系元素中的规则中的一个模式和部分。
主流的浏览器都支持对CSS的解析,应用到相应的元素上去。Selenium WebDriver使用CSS解析引擎来定位页面上的元素。CSS选择器提供多样的方法,规则和模式来定位页面上的元素。这也是相对我们后面说的XPath更加稳定和快速的方法。
使用CSS选择器,可以通过多样的方法来定位元素如Class,ID,属性值和在此秘籍中我们描述的一些文本内容方法。
1.8.使用XPath定位元素
XPath是XML路径语言,用来查询XML文档里中的节点。主流的浏览器都支持Xpath,因为HTML页面在DOM中表示为XHTML文档。
Xpath语言是基于XML文档的树结构,并提供了浏览树的能力,通过多样的标准来选择结点。
Selenium WebDriver支持使用Xpath表达式来定位元素。
利用Xpath来定位元素非常方便,但是,便捷的定位策略牺牲了系统的性能。
XPath和CSS中最重要的区别在于,Xpath可以向前和向后查询DOM结构的元素,而CSS只能向前查询。这意味着使用XPath可以通过子元来定位父元素。
在这个秘籍中,我们将探索一些基本的XPath查询来定位元素然后再学习一些XPath的高级应用。
如何实现如何实现
让我们探索一些Selenium WebDriver中基本的XPath表达式。Selenium WebDriver提供了Xpath()方法来定位元素。
通过绝对路径定位元素
和CSS绝对路径相似,XPath绝对路径适用于指定元素的位置。这里的一个例子就是使用绝对路径来定位用户名的字段。在每一个元素之间需要有一个空格。
WebElement userName =
driver.findElement(By.xpath("html/body/div/div/form/input"));
但是,这个策略有局限性,他需要参考整个页面的文档结构。如改变了,此元素的定位将会失败。
通过相对路径定位元素
用相对路径,我们可以直接找到元素而不管其在DOM中的位置。例如,我们可以通过如下方法来定位用户名字段,假设这个元素处于DOM中第一个:
WebElement userName = driver.findElement(By.xpath("//input"));
使用索引来定位元素
在前面的示例中,XPath查询将返回第一个DOM中元素。可能会有多个元素都匹配了XPath查询。如果元素不是第一个元素,我们也可以指定他的个数来找到它。例如在我们的登录表单,我们可以找到密码字段 - 第二个,方法如下:
WebElement passwd = driver.findElement(By.xpath("//input[2]"));
使用XPath及属性值定位元素
和CSS相似,我们可以在XPath中使用元素的属性来定位元素。在下面的例子中,可以使用ID属性来定位用户名字段。
WebElement userName =
driver.findElement(By.xpath("//input[@id='username']"));
另一个使用alt属性来定位image属性的例子:
WebElement previousButton =
driver.findElement(By.xpath("img[@alt='Previous']"));
你可以会遇到一个属性不足以来定位到一个元素的情况,你需要联合使用其他的属性来达到精确匹配。下面的例子中,使用多个属性来定位元素。
WebElement previousButton =
driver.findElement(By.xpath
("//input[@type='submit'][@value='Login']"));
使用XPath和and操作符也同样可以达到相同的效果
WebElement previousButton = driver.findElement
(By.xpath("//input[@type='submit'and @value='Login']"));
下面的例子中,使用or操作符任何一个属性满足也将可以对元素进行定位
WebElement previousButton = driver.findElement
(By.xpath("//input[@type='submit'or @value='Login']"));
使用XPath及属性名称定位元素
这个策略和之前的有些不同,我们只通过指定元素中属性的名称而不是属性的值来定位元素。例如,我们想要查找所有标签中,含有alt属性的元素。
List imagesWithAlt = driver.findElements
(By.xpath ("img[@alt]"));
部分属性值的匹配
类似于CSS选择器,XPath还提供了一种一些方法部分匹配属性来定位元素。这对于网页中的属性是动态变化的时候是非常有用的。例如,ASP.NET应用程序中动态生成id属性值。下面的表说明了使用这些XPath功能:
语法
例子
描述
starts-with()
input[starts-with(@id,'ctrl')]
例如,如果元素的ID为ctrl_12,将会匹配以ctrl开始的属性值。
ends-with()
input[ends-with(@id,'_userName')]
例如,如果元素的ID为a_1_userName,将会匹配以userName结尾的属性值。
contains()
Input[contains(@id,'userName')]
例如,如果元素的ID为panel_login_userName_textfield,将会匹配含有userName属性值。
使用值来匹配任意属性及元素
XPath可以匹配任意元素属性中指定的值。例如,在下面的XPath查询中,“userName”是指定的。XPath将会检查所有元素中是否有属性等于”userName”,并将其返回。
WebElement userName =
driver.findElement(By.xpath("//input[@*='username']"));
使用XPath轴来定位元素
XPath轴是借助于文档中元素与元素之间的关系来定位。下面有一个简单的的XPath轴的例子。
下面是用图形来表示HTML元素间的关系
轴
描述
例子
结果
ancestor
选择当前节结点所有的父类元素,包括祖先元素
//td[text()='Product 1']/ancestor::table
得到table元素
descendant
选择当前节点所有子元素
//table/
descendant::td/input
得到第三例第二行的input元素
following
选择当前元素结束标签后的所有元素
//td[text()='Product
1']/following::tr
得到第到第二行的tr元素
following-
sibling
选择当前元素后的兄弟元素
//td[text()='Product
1']/following-
sibling::td
得到第二行第二列的td元素
preceding
选取文档中当前节点的开始标签之前的所有节点
//td[text()='$150']/
preceding::tr
得到第一行tr
preceding-
sibling
选取当前节点之前的所有同级节点。
//td[text()='$150']/
preceding-sibling::td
得到第三行第一列的td
更多关于XPath轴请访问http://www.w3schools.com/xpath/xpath_axes.asp 。
Xpath是处理、查询浏览器DOM强大的语言,可以浏览DOM中的元素和属性。XPath也提供了一些规则、函数和语法来定位元素。
主流的浏览器都支持XPath,Selenium WebDriver也提供了通过XPath来定位元素的能力。
使用By类中的Xpath()方法可以定位元素。XPath的查询是慢于CSS选择器,因为XPath支持双向的查询。你可以通过元素的父,兄弟,子节点来定位元素。
1.9.使用文本元素
当你测试网页应用的时候,你也可能遇到开发人员没有分配任何属性给元素,这时候定位元素就会变得很困难。
使用CSS选择器或XPath,我们可以使用他的本文内容来定位元素。在这个秘籍中,我们将探索如何使用文本值来定位元素。
如何实现如何实现
使用文本来定位元素,CSS选择器和XPath提供了方法来通过文本定位元素。如果一个元素包含一个指定的文本,将会返回到测试。
使用CSS选择器伪类定位元素
CSS选择器提供了contains()伪类来通过指定文本定位元素。例如,你可以通过表格里的内容来定位单元格,方法如下:
WebElement cell =
driver.findElement(By.cssSelector("td:contains('Item 1')"));
contains()伪类接受一个被查询的文本作为参数。然后查询所有标签里包含指定文本的元素。(注:contains()方法已经被CSS3弃用了)
以百度首页为例,现在我想定位新闻链接
WebElement news =
driver.findElement(By.cssSelector("a:contains('新')"));
作为contains()的替代,你可以使用innerText属性(不支持Firefox)或textContent属性(支持Firefox),方法如下:
WebElement news =
driver.findElement(By.cssSelector("a[innerText='新闻']"));
或
WebElement news = driver.findElement
(By.cssSelector("a[textContent='新闻']"));
使用XPath的text函数
XPath提供了text()方法来定位指定文本的元素,方法如下:
WebElement cell = driver.findElement
(By.xpath("//td[contains(text(),'Item 1')]"));
这里contains()与text()函数一起使用。text()函数,返回完整的文本,contains()函数将检查是否包含此文本。
使用XPath精确文本定位元素
利用XPath,通过精确的文本来定位元素,方法如下:
WebElement cell = driver.findElement
(By.xpath("//td[.='Item 1']"));
CSS选择器和XPath提供基于元素文本内容方法来定位元素。这种当元素没有足够的属性或当没有其他策略时会很方便找到这些元素。
对于使用文本定位,无论是CSS选择器还是XPath都是搜索整个DOM,返回匹配的元素。
1.10.使用高级的CSS选择器定位元素
我们在之前学习了一些基本的CSS选择器,在此秘籍中,我们将探索用一些高级的CSS选择器来定位元素
如何实现如何实现
在1.7章节中,我们已经探索了一些基本的CSS选择器,让我们探索一些高级的CSS选择器,如相邻的兄弟结合伪类的使用。
查询子元素
CSS选择器提供了多种方法通过父元素来定位它的子元素。还是之前的例子
如果想定位表单中的用户名输入框,我们使用在其父子元素间使用“>”符号。
WebElement userName = driver.findElement
(By.cssSelector("form#loginForm > input"));
相似的使用nth-child()方法也可以定位成功,方法如下:
WebElement userName = driver.findElement
(By.cssSelector("form#loginForm :nth-child(2)"));
下列表格列出了使用伪类来定位子元素的例子:
伪类
例子
描述
:first-child
form#loginForm :first-child
定位表单里第一个子元素username标签
:last-child
form#loginForm :last-child
定位表单最后一个子元素Login按钮
:nth-child(2)
form#loginForm :nth-child(2)
定位表单中第二个子元素username的输入框
查询兄弟元素
利用CSS选择器,我们可以使用“+”操作符来定位兄弟元素。还是以百度首页为例
,可以使用下例方法来定位百度导航中的“网页”超链接
WebElement web =
driver.findElement(By.cssSelector("#nv a + b"));
#nv a定位到“新闻”链接,“+ b“后就找到其兄弟元素
使用用户操作伪类
使用用户的操作行为:focus伪类,定位焦点在input框中的元素,方法如下:
WebElement productDescription =
driver.findElement(By.cssSelector("input:focus"));
你也可以使:hover和:active伪类来定位元素
使用UI状态伪类
使用UI状态伪类,我们可以通过元素的各种状态来定位,如enabled,disable,checked。 下例表格给予了详细的说明
伪类
例子
描述
:enabled
input:enabled
定位所有属性为enable的input的元素
:disabled
input:disabled
定位所有属性为disabled的input的元素
:checked
input:checked
定位所有多选框属性为checked的元素
访问 http://www.w3schools.com/cssref/css_selectors.asp 查询更多CSS选择器的用法
1.11.使用jQuery选择器
jQuery选择器是jQuery库中非常重要的功能。jQuery选择器是基于CSS1-3选择器,加上一些额外的选择器。这些选择器和CSS选择器的使用方法很相似,允许开发人员简单快速的识别页面上的元素。同样可以定位HTML中的元素作为一个单独的元素或是一个元素集合。
jQuery选择器可以使用在那些不支持CSS选择器的浏览器上。
在这个秘籍中,我们将简单的探索如何在Selenium WebDriver中使用jQuery选择器
如何实现如何实现
以jQuery官网为例,网站本身已经自动加载了jQuery的库,所以我们可以在脚本中直接使用jQuery语法。下面的例子中我们想使用jQuery的选择器:even选出右侧导航栏中偶数(第一位是索引是0)超链接Download、Blog、Browser Support
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
WebDriver driver = new InternetExplorerDriver();
JavascriptExecutor jse = (JavascriptExecutor)driver;
@Test
public void jQueryTest() {
driver.get("http://www.jquery.com/");
List elements =
(List)jse.executeScript
("return jQuery.find" +
"('.menu-item a:even')");
assertEquals(3,elements.size());
assertEquals("Download",elements.get(0).getText());
assertEquals("Blog",elements.get(1).getText());
assertEquals("Browser Support",elements.get(2).getText());
driver.close();
}
}
Selenium WebDriver使用jQuery API增强了jQuery选择器,但是,我们需要确认页面以经加载了jQuery。jQuery API提供了find()方法来查询元素。我们需要使用JavaScriptExecutor类来执行jQuery的find()方法。
find()方法返回了符合查询条件的元素集合。更多jQuery选择器信息请查询 http://api.jquery.com/category/selectors/ 。
在使用jQuery选择器的时候,有的页面并未加载jQuery库,这时候你可以在加载页面的时候注入jQuery库,方法如下:
private void injectjQueryIfNeeded() {
if (!jQueryLoaded())
injectjQuery();
}
public Boolean jQueryLoaded() {
Boolean loaded;
try {
loaded = (Boolean) driver.executeScript("return
jQuery()!=null");
} catch (WebDriverException e) {
loaded = false;
}
return loaded;
}
public void injectjQuery() {
//在head中拼出加载jquery的html
driver.executeScript(" var headID =
document.getElementsByTagName(\"head\")[0];"
+ "var newScript = document.createElement('script');"
+ "newScript.type = 'text/javascript';"
+ "newScript.src = 'http://ajax.googleapis.com/
ajax/libs/jquery/1.7.2/jquery.min.js';"
+ "headID.appendChild(newScript);");
}
还是以百度首页为例,百度首页没有jQuery库。我们想定位百度导航栏上面的所有超链接元素,并输出结果。
package com.example.tests;
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.openqa.selenium.*;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class Selenium2 {
WebDriver driver = new InternetExplorerDriver();
JavascriptExecutor jse = (JavascriptExecutor)driver;
@Test
public void jQueryTest() {
driver.get("http://www.baidu.com/");
injectjQueryIfNeeded();
List elements =
(List)jse.executeScript
("return jQuery.find('#nv a')");
assertEquals(7,elements.size()); //验证超链接的数量
for (int i = 0; i < elements.size(); i++) {
System.out.print(elements.get(i).getText() + "、");
}
driver.close();
}
private void injectjQueryIfNeeded() {
if (!jQueryLoaded())
injectjQuery();
}
//判断是已加载jQuery
public Boolean jQueryLoaded() {
Boolean loaded;
try {
loaded = (Boolean)jse.executeScript("return " +
"jQuery()!=null");
} catch (WebDriverException e) {
loaded = false;
}
return loaded;
}
//通过注入jQuery
public void injectjQuery() {
jse.executeScript(" var headID = "
+"document.getElementsByTagName(\"head\")[0];"
+ "var newScript = document.createElement('script');"
+ "newScript.type = 'text/javascript';"
+ "newScript.src = "
+"'http://ajax.googleapis.com/ajax/"
+"libs/jquery/1.7.2/jquery.min.js';"
+ "headID.appendChild(newScript);");
}
}
injectjQueryIfNeeded()方法首先通过jQueryLoaded()方法来判断网页中是否加有jQuery对象。如果没有,再调用injectjQuery()方法通过增加一个
你可能感兴趣的:(selenium功能自动化测试)
- 多线程编程之卫生间
周凡杨
java并发卫生间线程厕所
如大家所知,火车上车厢的卫生间很小,每次只能容纳一个人,一个车厢只有一个卫生间,这个卫生间会被多个人同时使用,在实际使用时,当一个人进入卫生间时则会把卫生间锁上,等出来时打开门,下一个人进去把门锁上,如果有一个人在卫生间内部则别人的人发现门是锁的则只能在外面等待。问题分析:首先问题中有两个实体,一个是人,一个是厕所,所以设计程序时就可以设计两个类。人是多数的,厕所只有一个(暂且模拟的是一个车厢)。
- How to Install GUI to Centos Minimal
sunjing
linuxInstallDesktopGUI
http://www.namhuy.net/475/how-to-install-gui-to-centos-minimal.html
I have centos 6.3 minimal running as web server. I’m looking to install gui to my server to vnc to my server. You can insta
- Shell 函数
daizj
shell函数
Shell 函数
linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。
shell中函数的定义格式如下:
[function] funname [()]{
action;
[return int;]
}
说明:
1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
2、参数返回
- Linux服务器新手操作之一
周凡杨
Linux 简单 操作
1.whoami
当一个用户登录Linux系统之后,也许他想知道自己是发哪个用户登录的。
此时可以使用whoami命令。
[ecuser@HA5-DZ05 ~]$ whoami
e
- 浅谈Socket通信(一)
朱辉辉33
socket
在java中ServerSocket用于服务器端,用来监听端口。通过服务器监听,客户端发送请求,双方建立链接后才能通信。当服务器和客户端建立链接后,两边都会产生一个Socket实例,我们可以通过操作Socket来建立通信。
首先我建立一个ServerSocket对象。当然要导入java.net.ServerSocket包
ServerSock
- 关于框架的简单认识
西蜀石兰
框架
入职两个月多,依然是一个不会写代码的小白,每天的工作就是看代码,写wiki。
前端接触CSS、HTML、JS等语言,一直在用的CS模型,自然免不了数据库的链接及使用,真心涉及框架,项目中用到的BootStrap算一个吧,哦,JQuery只能算半个框架吧,我更觉得它是另外一种语言。
后台一直是纯Java代码,涉及的框架是Quzrtz和log4j。
都说学前端的要知道三大框架,目前node.
- You have an error in your SQL syntax; check the manual that corresponds to your
林鹤霄
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'option,changed_ids ) values('0ac91f167f754c8cbac00e9e3dc372
- MySQL5.6的my.ini配置
aigo
mysql
注意:以下配置的服务器硬件是:8核16G内存
[client]
port=3306
[mysql]
default-character-set=utf8
[mysqld]
port=3306
basedir=D:/mysql-5.6.21-win
- mysql 全文模糊查找 便捷解决方案
alxw4616
mysql
mysql 全文模糊查找 便捷解决方案
2013/6/14 by 半仙 [email protected]
目的: 项目需求实现模糊查找.
原则: 查询不能超过 1秒.
问题: 目标表中有超过1千万条记录. 使用like '%str%' 进行模糊查询无法达到性能需求.
解决方案: 使用mysql全文索引.
1.全文索引 : MySQL支持全文索引和搜索功能。MySQL中的全文索
- 自定义数据结构 链表(单项 ,双向,环形)
百合不是茶
单项链表双向链表
链表与动态数组的实现方式差不多, 数组适合快速删除某个元素 链表则可以快速的保存数组并且可以是不连续的
单项链表;数据从第一个指向最后一个
实现代码:
//定义动态链表
clas
- threadLocal实例
bijian1013
javathreadjava多线程threadLocal
实例1:
package com.bijian.thread;
public class MyThread extends Thread {
private static ThreadLocal tl = new ThreadLocal() {
protected synchronized Object initialValue() {
return new Inte
- activemq安全设置—设置admin的用户名和密码
bijian1013
javaactivemq
ActiveMQ使用的是jetty服务器, 打开conf/jetty.xml文件,找到
<bean id="adminSecurityConstraint" class="org.eclipse.jetty.util.security.Constraint">
<p
- 【Java范型一】Java范型详解之范型集合和自定义范型类
bit1129
java
本文详细介绍Java的范型,写一篇关于范型的博客原因有两个,前几天要写个范型方法(返回值根据传入的类型而定),竟然想了半天,最后还是从网上找了个范型方法的写法;再者,前一段时间在看Gson, Gson这个JSON包的精华就在于对范型的优雅简单的处理,看它的源代码就比较迷糊,只其然不知其所以然。所以,还是花点时间系统的整理总结下范型吧。
范型内容
范型集合类
范型类
- 【HBase十二】HFile存储的是一个列族的数据
bit1129
hbase
在HBase中,每个HFile存储的是一个表中一个列族的数据,也就是说,当一个表中有多个列簇时,针对每个列簇插入数据,最后产生的数据是多个HFile,每个对应一个列族,通过如下操作验证
1. 建立一个有两个列族的表
create 'members','colfam1','colfam2'
2. 在members表中的colfam1中插入50*5
- Nginx 官方一个配置实例
ronin47
nginx 配置实例
user www www;
worker_processes 5;
error_log logs/error.log;
pid logs/nginx.pid;
worker_rlimit_nofile 8192;
events {
worker_connections 4096;}
http {
include conf/mim
- java-15.输入一颗二元查找树,将该树转换为它的镜像, 即在转换后的二元查找树中,左子树的结点都大于右子树的结点。 用递归和循环
bylijinnan
java
//use recursion
public static void mirrorHelp1(Node node){
if(node==null)return;
swapChild(node);
mirrorHelp1(node.getLeft());
mirrorHelp1(node.getRight());
}
//use no recursion bu
- 返回null还是empty
bylijinnan
javaapachespring编程
第一个问题,函数是应当返回null还是长度为0的数组(或集合)?
第二个问题,函数输入参数不当时,是异常还是返回null?
先看第一个问题
有两个约定我觉得应当遵守:
1.返回零长度的数组或集合而不是null(详见《Effective Java》)
理由就是,如果返回empty,就可以少了很多not-null判断:
List<Person> list
- [科技与项目]工作流厂商的战略机遇期
comsci
工作流
在新的战略平衡形成之前,这里有一个短暂的战略机遇期,只有大概最短6年,最长14年的时间,这段时间就好像我们森林里面的小动物,在秋天中,必须抓紧一切时间存储坚果一样,否则无法熬过漫长的冬季。。。。
在微软,甲骨文,谷歌,IBM,SONY
- 过度设计-举例
cuityang
过度设计
过度设计,需要更多设计时间和测试成本,如无必要,还是尽量简洁一些好。
未来的事情,比如 访问量,比如数据库的容量,比如是否需要改成分布式 都是无法预料的
再举一个例子,对闰年的判断逻辑:
1、 if($Year%4==0) return True; else return Fasle;
2、if ( ($Year%4==0 &am
- java进阶,《Java性能优化权威指南》试读
darkblue086
java性能优化
记得当年随意读了微软出版社的.NET 2.0应用程序调试,才发现调试器如此强大,应用程序开发调试其实真的简单了很多,不仅仅是因为里面介绍了很多调试器工具的使用,更是因为里面寻找问题并重现问题的思想让我震撼,时隔多年,Java已经如日中天,成为许多大型企业应用的首选,而今天,这本《Java性能优化权威指南》让我再次找到了这种感觉,从不经意的开发过程让我刮目相看,原来性能调优不是简单地看看热点在哪里,
- 网络学习笔记初识OSI七层模型与TCP协议
dcj3sjt126com
学习笔记
协议:在计算机网络中通信各方面所达成的、共同遵守和执行的一系列约定 计算机网络的体系结构:计算机网络的层次结构和各层协议的集合。 两类服务: 面向连接的服务通信双方在通信之前先建立某种状态,并在通信过程中维持这种状态的变化,同时为服务对象预先分配一定的资源。这种服务叫做面向连接的服务。 面向无连接的服务通信双方在通信前后不建立和维持状态,不为服务对象
- mac中用命令行运行mysql
dcj3sjt126com
mysqllinuxmac
参考这篇博客:http://www.cnblogs.com/macro-cheng/archive/2011/10/25/mysql-001.html 感觉workbench不好用(有点先入为主了)。
1,安装mysql
在mysql的官方网站下载 mysql 5.5.23 http://www.mysql.com/downloads/mysql/,根据我的机器的配置情况选择了64
- MongDB查询(1)——基本查询[五]
eksliang
mongodbmongodb 查询mongodb find
MongDB查询
转载请出自出处:http://eksliang.iteye.com/blog/2174452 一、find简介
MongoDB中使用find来进行查询。
API:如下
function ( query , fields , limit , skip, batchSize, options ){.....}
参数含义:
query:查询参数
fie
- base64,加密解密 经融加密,对接
y806839048
经融加密对接
String data0 = new String(Base64.encode(bo.getPaymentResult().getBytes(("GBK"))));
String data1 = new String(Base64.decode(data0.toCharArray()),"GBK");
// 注意编码格式,注意用于加密,解密的要是同
- JavaWeb之JSP概述
ihuning
javaweb
什么是JSP?为什么使用JSP?
JSP表示Java Server Page,即嵌有Java代码的HTML页面。使用JSP是因为在HTML中嵌入Java代码比在Java代码中拼接字符串更容易、更方便和更高效。
JSP起源
在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变。
如果使用Servl
- apple watch 指南
啸笑天
apple
1. 文档
WatchKit Programming Guide(中译在线版 By @CocoaChina) 译文 译者 原文 概览 - 开始为 Apple Watch 进行开发 @星夜暮晨 Overview - Developing for Apple Watch 概览 - 配置 Xcode 项目 - Overview - Configuring Yo
- java经典的基础题目
macroli
java编程
1.列举出 10个JAVA语言的优势 a:免费,开源,跨平台(平台独立性),简单易用,功能完善,面向对象,健壮性,多线程,结构中立,企业应用的成熟平台, 无线应用 2.列举出JAVA中10个面向对象编程的术语 a:包,类,接口,对象,属性,方法,构造器,继承,封装,多态,抽象,范型 3.列举出JAVA中6个比较常用的包 Java.lang;java.util;java.io;java.sql;ja
- 你所不知道神奇的js replace正则表达式
qiaolevip
每天进步一点点学习永无止境纵观千象regex
var v = 'C9CFBAA3CAD0';
console.log(v);
var arr = v.split('');
for (var i = 0; i < arr.length; i ++) {
if (i % 2 == 0) arr[i] = '%' + arr[i];
}
console.log(arr.join(''));
console.log(v.r
- [一起学Hive]之十五-分析Hive表和分区的统计信息(Statistics)
superlxw1234
hivehive分析表hive统计信息hive Statistics
关键字:Hive统计信息、分析Hive表、Hive Statistics
类似于Oracle的分析表,Hive中也提供了分析表和分区的功能,通过自动和手动分析Hive表,将Hive表的一些统计信息存储到元数据中。
表和分区的统计信息主要包括:行数、文件数、原始数据大小、所占存储大小、最后一次操作时间等;
14.1 新表的统计信息
对于一个新创建
- Spring Boot 1.2.5 发布
wiselyman
spring boot
Spring Boot 1.2.5已在7月2日发布,现在可以从spring的maven库和maven中心库下载。
这个版本是一个维护的发布版,主要是一些修复以及将Spring的依赖提升至4.1.7(包含重要的安全修复)。
官方建议所有的Spring Boot用户升级这个版本。
项目首页 | 源
|