INTRODUCTION
THE SELENIUM PROJECT AND TOOLS
Selenium controls web browsers
Selenium is many things, but at its core it's a toolset for web browser automation that uses the best techniques available to remotely control browser instances and emulate a user's interaction with the browser.
It allows users to simulate common activities performed by end-users; entering text into fields, selecting drop-down values and checking boxes, and clicking links in documents. It also provides many other controls such as mouse movement, arbitrary JavaScript execution, and much more.
Although used primarily for front-end testing of websites, Selenium is at its core a browser user agent library. The interfaces are ubiquitous to their application, which encourages composition with other libraries to suit your purpose.
One interface to rule them all
One of the project's guiding principles is to support a common interface for all (major) browser technologies. Web browsers are incredibly complex, highly engineered applications, performing their operations in completely different ways but which frequently look the same while doing so. Even though the text is rendered in the same fonts, the images are displayed in the same place and the links take you to the same destination. What is happening underneath is as different as night and day. Selenium “abstracts” these differences, hiding their details and intricacies from the person writing the code. This allows you to write several lines of code to perform a complicated workflow, but these same lines will execute on Firefox, Internet Explorer, Chrome, and all other supported browsers.
Tools and support
Selenium's minimalist design approach gives it versatility to be included as a component in bigger applications. The surrounding infrastructure provided under the Selenium umbrella gives you the tools to put together your own grid of browsers so tests can be run on different browsers and multiple operating systems across a range of machines.
Imagine a bank of computers in your server room or data centre all firing up browsers at the same time hitting your site's links, forms, and tables—testing your application 24 hours a day. Through the simple programming interface provided for the most common languages, these tests will run tirelessly in parallel, reporting back to you when errors occur.
It's an aim to help make this a reality for you, by providing users with tools and documentation to not only control browsers, but to make it easy to scale and deploy such grids.
Who uses Selenium
Many of the most important companies in the world have adopted Selenium for their browser-based testing, often replacing years-long efforts involving other proprietary tools. As it has grown in popularity, so have its requirements and challenges multiplied.
As the web becomes more complicated and new technologies are added to websites, it's the mission of this project to keep up with them where possible. Being an open source project, this support is provided through the generous donation of time from many volunteers, every one of which has a “day job”.
Another mission of the project is to encourage more volunteers to partake in this effort, and build a strong community so that the project can continue to keep up with emerging technologies and remain a dominant platform for functional test automation.
History
When Selenium 1 was released in 2004, it was out of the necessity to reduce time spent manually verifying consistent behaviour in the front-end of a web application. It made use of what tools were available at the time, and relied heavily on the injection of JavaScript to the web page under test to emulate a user's interaction.
Whilst JavaScript is a good tool to let you introspect the properties of the DOM and to do certain client-side observations that you would otherwise not be able to do, it falls short on the ability to naturally replicate a user's interactions as if the mouse and keyboard are being used.
Since then, Selenium has grown and matured a lot, into a tool widely used by many—if not most—of the largest organisations around the world. Selenium has gone from a homebrewed test automation toolkit developed at Thoughtworks for a niché audience and a specific use case, to the world's de facto browser automation library.
Just as Selenium RC made use of the tools of the trade available at the time, Selenium WebDriver drives that tradition on by taking the browser interaction part to the browser vendor's home turf, and asking them to take responsibility of the backend, browser-facing implementations. Recently this work has evolved into a W3C standardisation process where the goal is to turn the WebDriver component in Selenium into the du jeur remote control library for user agents.
ON TEST AUTOMATION
First, start by asking yourself whether or not you really need to use a browser. Odds are good that, at some point, if you're working on a complex web application, you will need to open a browser and actually test it.
Functional end-user tests such as Selenium tests are expensive to run, however. Furthermore, they typically require substantial infrastructure to be in place to be run effectively. It's a good rule to always ask yourself if what you want to test can be done using more lightweight test approaches such as unit tests or with a lower-level approach.
Once you have made the determination that you're in the web browser testing business, and you have your Selenium environment ready to begin writing tests, you will generally perform some combination of three steps:
- Set up the data
- Perform a discrete set of actions
- Evaluate the results
You will want to keep these steps as short as possible; one to two operations should be enough much of the time. Browser automation has the reputation of being “flaky”, but in reality that is because users frequently demand too much of it. In later chapters, we will return to techniques you can use to mitigate apparent intermittent problems in tests, in particular on how to overcome race conditions between the browser and WebDriver.
By keeping your tests short and using the web browser only when you have absolutely no alternative, you can have many tests with minimal flake.
A distinct advantage of Selenium tests are their inherent ability to test all components of the application, from backend to frontend, from a user's perspective. So in other words, whilst functional tests may be expensive to run, they also encompass large business-critical portions at one time.
Testing requirements
As mentioned before, Selenium tests can be expensive to run. To what extent depends on the browser you're running the tests against, but historically browsers' behaviour has varied so much that it has often been a stated goal to cross-test against multiple browsers.
Selenium allows you to run the same instructions against multiple browsers on multiple operating systems, but the enumeration of all the possible browsers, their different versions, and the many operating systems they run on will quickly become a non-trival undertaking.
Let’s start with an example
Larry has written a web site which allows users to order their own custom unicorns.
The general workflow (what we'll call the “happy path”) is something like this:
- Create an account
- Configure their unicorn
- Add her to the shopping cart
- Check out and pay
- Give feedback about their unicorn
It would be tempting to write one grand Selenium script to perform all these operations–many will try.Resist the temptation! Doing so will result in a test that (a) takes a long time, (b) will be subject to some common issues around page rendering timing issues, and (c) is such that if it fails, it won't give you a concise, “glanceable” method for diagnosing what went wrong.
The preferred strategy for testing this scenario would be to break it down to a series of independent, speedy tests, each of which has one “reason” to exist.
Let's pretend you want to test the second step: Configuring your unicorn. It will perform the following actions:
- Create an account
- Configure a unicorn
Note that we're skipping the rest of these steps– we will test the rest of the workflow in other small, discrete test cases, after we're done with this one.
To start off, you need to create an account. Here you have some choices to make:
- Do you want to use an existing account?
- Do you want to create a new account?
- Are there any special properties of such a user that need to be taken into account before configuration begins?
Regardless of how you answer this question, the solution is to make it part of the “set up the data” portion of the test– if Larry has exposed an API which enables you (or anyone) to create and update user accounts, be sure to use that to answer this question– if possible, you want to launch the browser only after you have a user “in hand”, whose credentials you can just log in with.
If each test for each workflow begins with the creation of a user account, many seconds will be added to the execution of each test. Calling an API and talking to a database are quick, “headless” operations that don't require the expensive process of opening a browser, navigating to the right pages, clicking and waiting for the forms to be submitted, etc.
Ideally, you can address this set-up phase in one line of code, which will execute before any browser is launched:
// Create a user who has read-only permissions--they can configure a unicorn, // but they do not have payment information set up, nor do they have // administrative privileges. At the time the user is created, its email // address and password are randomly generated--you don't even need to // know them. User user = UserFactory.createCommonUser(); //This method is defined elsewhere. // Log in as this user. // Logging in on this site takes you to your personal "My Account" page, so the // AccountPage object is returned by the loginAs method, allowing you to then // perform actions from the AccountPage. AccountPage accountPage = loginAs(user.getEmail(), user.getPassword());
As you can imagine, the UserFactory can be extended to provide methods such as createAdminUser(), and createUserWithPayment(). The point is, these two lines of code do not distract you from the ultimate purpose of this test: configuring a unicorn.
The intricacies of the Page Object model will be discussed in later chapters, but we will introduce the concept here:
Your tests should be composed of actions, performed from the user's point of view, within the context of pages in the site. These pages are stored as objects, which will contain specific information about how the web page is composed and how actions are performed– very little of which should concern you as a tester.
What kind of unicorn do you want? You might want pink, but not necessarily. Purple has been quite popular lately. Does she need sunglasses? Star tattoos? These choices, while difficult, are your primary concern as a tester– you need to ensure that your order fulfillment center sends out the right unicorn to the right person, and that starts with these choices.
Notice that nowhere in that paragraph do we talk about buttons, fields, drop-downs, radio buttons, or web forms. Neither should your tests! You want to write your code like the user trying to solve their problem. Here is one way of doing this (continuing from the previous example):
// The Unicorn is a top-level Object--it has attributes, which are set here. // This only stores the values; it does not fill out any web forms or interact // with the browser in any way. Unicorn sparkles = new Unicorn("Sparkles", UnicornColors.PURPLE, UnicornAccessories.SUNGLASSES, UnicornAdornments.STAR_TATTOOS); // Since we're already "on" the account page, we have to use it to get to the // actual place where you configure unicorns. Calling the "Add Unicorn" method // takes us there. AddUnicornPage addUnicornPage = accountPage.addUnicorn(); // Now that we're on the AddUnicornPage, we will pass the "sparkles" object to // its createUnicorn() method. This method will take Sparkles' attributes, // fill out the form, and click submit. UnicornConfirmationPage unicornConfirmationPage = addUnicornPage.createUnicorn(sparkles);
Now that you've configured your unicorn, you need to move on to step 3: making sure it actually worked.
// The exists() method from UnicornConfirmationPage will take the Sparkles // object--a specification of the attributes you want to see, and compare // them with the fields on the page. Assert.assertTrue("Sparkles should have been created, with all attributes intact", unicornConfirmationPage.exists(sparkles));
Note that the tester still hasn't done anything but talk about unicorns in this code– no buttons, no locators, no browser controls. This method of modelling the application allows you to keep these test-level commands in place and unchanging, even if Larry decides next week that he no longer likes Ruby-on-Rails and decides to re-implement the entire site in the latest Haskell bindings with a Fortran front-end.
Your page objects will require some small maintenance in order to conform to the site redesign, but these tests will remain the same. Taking this basic design, you will want to keep going through your workflows with the fewest browser-facing steps possible. Your next workflow will involve adding a unicorn to the shopping cart. You will probably want many iterations of this test in order to make sure the cart is keeping its state properly: Is there more than one unicorn in the cart before you start? How many can fit in the shopping cart? If you create more than one with the same name and/or features, will it break? Will it only keep the existing one or will it add another?
Each time you move through the workflow, you want to try to avoid having to create an account, login as the user, and configure the unicorn. Ideally, you'll be able to create an account and pre-configure a unicorn via the API or database. Then all you have to do is log in as the user, locate Sparkles, and add her to the cart.
TYPES OF TESTING
TODO: Add paragraphs about acceptance testing, performance testing, load testing, regression testing, test driven development, and/or behavior-driven development (JBehave, Capybara, & Robot Framework), with how they relate to Selenium.
ABOUT THIS DOCUMENTATION
These docs, like the code itself, are maintained 100% by volunteers within the Selenium community. Many have been using it since its inception, but many more have only been using it for a short while, and have given their time to help improve the on-boarding experience for new users.
If there is an issue with the documentation, we want to know! The best way to communicate an issue is to visit https://github.com/seleniumhq/docs/issues and search to see whether or not the issue has been filed already. If not, feel free to open one!
Many members of the community frequent the #selenium IRC channel at irc.freenode.net. Feel free to drop in and ask questions and if you get help which you think could be of use within these documents, be sure to add your contribution! We can update these documents, but it's much easier for everyone when we get contributions from outside the normal committers.
介绍
SELENIUM项目和工具
Selenium控制网页浏览器
Selenium包含多东西,但其核心是一个Web浏览器自动化工具集,它是应用于远程控制浏览器和模拟用户与浏览器交互的最佳技术。
它容许用户模拟终端用户执行常见操做; 在字段中输入文本,选择下拉值和复选框,而后单击文档中的连接。它还提供许多其余控件,如鼠标移动,任意JavaScript执行等。
虽然Selenium主要用于网站的前端测试,但它的核心是浏览器用户代理库。这些接口在应用程序中无处不在,它鼓励与其余库合成以适应您的目的。
一个接口来管理他们
该项目的指导原则之一是支持全部(主要)浏览器技术的通用界面。Web浏览器是很是复杂且高度工程化的应用程序,它们以彻底不一样的方式执行其操做,尽管在执行操做时常常看起来相同。即便文本以相同的字体呈现,图像也会显示在相同的位置,而且连接会将您带到相同的目的地。下面发生的事情就像白天和黑夜同样不一样。Selenium“摘录”了这些差别,隐藏了人们编写代码的细节和复杂性。这让您编写几行代码就能执行复杂的工做流程,用同一套代码就能Firefox,Internet Explorer,Chrome和全部其余支持的浏览器上执行。
工具和支持
selenium的极简主义设计方法赋予其多功能性,可做为更大应用中的组件。Selenium伞下提供的周边基础架构为您提供了将本身的浏览器网格放在一块儿的工具, 这样测试能够在各类机器上的不一样浏览器和多个操做系统上运行。
想象一下,您服务器机房或数据中心内的一组计算机会同时触发浏览器,同时击中您网站的连接,表格和表格 - 天天24小时测试您的应用程序。经过为大多数经常使用语言提供的简单编程界面,这些测试能够不知疲倦地并行运行,并在发生错误时向您报告。
咱们的目标是经过为用户提供工具和文档来帮助您实现这一目标,不只能够控制浏览器,还能够轻松扩展和部署此类网格。
谁使用Selenium
世界上许多最重要的公司都采用Selenium进行基于浏览器的测试,一般取代涉及其余专有工具的长达数年的努力。随着它愈来愈受欢迎,它的要求和挑战也愈来愈大。
随着网络变得愈来愈复杂,新技术被添加到网站中,这个项目的使命就是在可能的状况下跟上它们。做为一个开源项目,这种支持是经过从许多志愿者慷慨捐赠的时间提供的,每一个志愿者都有一份“平常工做”。
该项目的另外一个使命是鼓励更多的志愿者参与这项工做,并创建一个强大的社区,以便该项目可以继续跟上新兴技术的发展,并继续成为功能测试自动化的主要平台。
历史
当Selenium 1于2004年发布时,减小了在Web应用程序的前端手动验证一致行为的时间,这是没必要要的。它利用了当时可用的工具,并严重依赖将JavaScript注入被测网页以模拟用户的交互。
虽然JavaScript是一种很好的工具,可让您反思DOM的属性并执行某些客户端观察,不然您没法执行此操做,但它没法天然复制用户的交互,就像鼠标和正在使用键盘。
从那时起,Selenium已经成长并成熟了许多,成为全世界许多(甚至是大多数)大型组织所普遍使用的工具。Selenium已经从在Thoughttworks开发的一个自制测试自动化工具包中为niché的观众和一个特定的使用案例转向了世界上事实上的浏览器自动化库。
就像Selenium RC利用当时可用的交易工具同样, Selenium WebDriver经过将浏览器交互部分提供给浏览器供应商的主页来驱动这一传统,并要求他们负责后端,面向浏览器的实现。最近,这项工做已经发展成为一个W3C标准化流程,其目标是将Selenium中的WebDriver组件转变为用户代理的du jeur远程控制库。
自动化测试
首先,先问本身是否真的须要使用浏览器。在某些状况下,若是您正在处理一个复杂的Web应用程序,您将须要打开浏览器并进行实际测试。
可是,功能最终用户测试(如Selenium测试)运行起来很昂贵。此外,他们一般须要大量基础设施才能有效运行。经过使用更轻量级的测试方法(如单元测试或低级方法)来老是问本身是否想要测试什么是一个很好的规则。
一旦你肯定你在网络浏览器测试业务,而且你的Selenium环境准备好开始编写测试,你一般会执行三个步骤的组合:
您将但愿尽量缩短这些步骤; 一到两次操做应该足够多。浏览器自动化具备“片状”的声誉,但实际上这是由于用户常常要求太多。在后面的章节中,咱们将回到能够用来缓解测试中明显的间歇性问题的技术,特别是如何克服 浏览器和WebDriver之间的竞争条件。
经过保持简短的测试和仅在彻底没有其余选择的状况下使用Web浏览器,您能够进行许多测试,只需不多的剥落。
Selenium测试的一个明显优点是其从用户的角度来测试应用程序的全部组件(从后端到前端)的内在能力。换句话说,尽管功能测试运行起来可能很昂贵,但它们同时也包含大量业务关键部分。
测试要求
如前所述,Selenium测试的运行可能很昂贵。在多大程度上取决于您正在运行测试的浏览器,但从历史上看,浏览器的行为差别很是大,所以常常是针对多个浏览器进行交叉测试的既定目标。
Selenium容许您针对多个操做系统上的多个浏览器运行相同的指令,可是全部可能的浏览器,它们的不一样版本以及它们所运行的许多操做系统的枚举将很快成为一项非调整性任务。
咱们从一个例子开始
Larry编写了一个网站,容许用户订购他们本身的独角兽。
通常的工做流程(咱们称之为“开心路径”)就像这样:
- 建立一个账户
- 配置他们的独角兽
- 将她添加到购物车
- 退房并付款
- 提供关于他们的独角兽的反馈
编写一个盛大的Selenium脚原本执行全部这些操做是颇有诱惑力的 - 不少人都会尝试。 抵制诱惑! 这样作会致使测试(a)须要很长时间,(b)会受到围绕页面渲染时间问题的一些常见问题的影响,而且(c)若是它失败了,它不会给你一个简洁,“可视”的方法来诊断出错的地方。
测试这种状况的首选策略是将其分解为一系列独立,快速的测试,其中每一个测试都存在一个“缘由”。
让咱们伪装你想要测试第二步:配置你的独角兽。它将执行如下操做:
请注意,咱们正在跳过其他的这些步骤 - 在完成这一步以后,咱们将在其余小型离散测试案例中测试其他的工做流程。
首先,您须要建立一个账户。在这里你能够作出一些选择:
- 你想使用现有的账户吗?
- 你想建立一个新账户吗?
- 在配置开始以前是否须要考虑这种用户的任何特殊属性?
不管您如何回答此问题,解决方案都是使其成为测试的“设置数据”部分的一部分 - 若是Larry公开了API(使您(或任何人)能够建立和更新用户账户的API),请确保使用它来回答这个问题 - 若是可能的话,你只有在你有一个用户“在手”以后才能启动浏览器,你的用户凭据能够登陆。
若是每一个工做流程的每一个测试都是从建立一个用户账户开始的,那么每一个测试的执行都会添加不少秒。调用API和与数据库交谈是快速的“无头”操做,不须要昂贵的过程来打开浏览器,浏览正确的页面,单击并等待表单提交等。
理想状况下,您能够在一行代码中解决这个设置阶段,这将在任何浏览器启动以前执行:
建立具备只读权限的用户——它们能够配置独角兽,但它们没有设置支付信息,也没有管理权限。在用户建立时,它的电子邮件地址和密码是随机生成的——甚至不须要知道它们。
// Create a user who has read-only permissions--they can configure a unicorn, // but they do not have payment information set up, nor do they have // administrative privileges. At the time the user is created, its email // address and password are randomly generated--you don't even need to // know them. User user = UserFactory.createCommonUser(); //This method is defined elsewhere.建立一个对象 登陆此网站。登陆到您的我的“个人账户”页面,所以,经过LogiNAS方法返回ActudioPage对象,容许您从ActudiPage执行操做。 // Log in as this user. // Logging in on this site takes you to your personal "My Account" page, so the // AccountPage object is returned by the loginAs method, allowing you to then // perform actions from the AccountPage. AccountPage accountPage = loginAs(user.getEmail(), user.getPassword());// 填入用户名和密码
正如你能够想象的那样,UserFactory能够扩展为提供诸如createAdminUser()和的方法createUserWithPayment()。问题是,这两行代码不会分散您的注意力,使其不能完成此测试的最终目的:配置独角兽。
页面对象模型
的复杂性 将在后面的章节中讨论,但咱们将在这里介绍这个概念:
您的测试应该由站点中页面上下文中从用户角度执行的操做组成。这些页面存储为对象,其中将包含关于如何组成网页以及如何执行操做的特定信息 - 其中不多应该将您做为测试人员。
你想要什么样的独角兽?你可能想粉红色,但不必定。紫色近来颇受欢迎。她须要太阳镜吗?星纹身?这些选择虽然困难,但做为测试人员是您的主要关注点,您须要确保您的订单履行中心将正确的独角兽发送给合适的人员,并从这些选择开始。
请注意,该段落中没有关于按钮,字段,下拉列表,单选按钮或Web表单的介绍。 你的测试也不该该! 你想写你的代码,像用户试图解决他们的问题。这是作这件事的一种方法(继续前面的例子):
// The Unicorn is a top-level Object--it has attributes, which are set here. // This only stores the values; it does not fill out any web forms or interact // with the browser in any way.
独角兽是一个顶层对象,它具备属性,这里设置了属性。这只存储值;它不填写任何Web窗体或以任何方式与浏览器交互。 Unicorn sparkles = new Unicorn("Sparkles", UnicornColors.PURPLE, UnicornAccessories.SUNGLASSES, UnicornAdornments.STAR_TATTOOS); // Since we're already "on" the account page, we have to use it to get to the // actual place where you configure unicorns. Calling the "Add Unicorn" method // takes us there.
由于咱们已经在“账号”页面上,因此咱们必须使用它来到达配置独角兽的实际位置。调用“添加独角兽”方法将咱们带到那里。
AddUnicornPage addUnicornPage = accountPage.addUnicorn(); // Now that we're on the AddUnicornPage, we will pass the "sparkles" object to // its createUnicorn() method. This method will take Sparkles' attributes, // fill out the form, and click submit.
既然咱们在AddUnicornPage上,咱们将把“Sparkles”对象传递给它的createUnicorn()方法。此方法将采起Sparkles属性,填写表单,而后单击提交。 UnicornConfirmationPage unicornConfirmationPage = addUnicornPage.createUnicorn(sparkles);
// The exists() method from UnicornConfirmationPage will take the Sparkles // object--a specification of the attributes you want to see, and compare // them with the fields on the page.
从UnicornConfirmationPage中的exists()方法将使用Sparkles对象——您但愿看到的属性的规范,并将其与页面上的字段进行比较。 Assert.assertTrue("Sparkles should have been created, with all attributes intact", unicornConfirmationPage.exists(sparkles));
请注意,测试人员尚未作任何事情,只是谈论这个代码中的独角兽 - 没有按钮,没有定位器,没有浏览器控件。即便下周Larry决定再也不喜欢Ruby on Rails并决定在最新的Haskell绑定中从新实现整个站点,这种对应用程序进行建模的方法也容许您保持这些测试级命令的位置和不变。与Fortran前端。
你的页面对象将须要一些小的维护,以符合网站的从新设计,但这些测试将保持不变。采用这种基本设计,您将但愿经过尽量少的面向浏览器的步骤继续完成工做流程。您的下一个工做流程将涉及在购物车中添加独角兽。为了确保购物车保持其状态,您可能须要进行屡次此测试:在您开始以前,购物车中是否有多个独角兽?购物车中可装多少个?若是您建立具备相同名称和/或功能的多个,它会中断吗?它只会保留现有的或将添加另外一个?
每次移动工做流程时,都要尽可能避免建立帐户,以用户身份登陆并配置独角兽。理想状况下,您能够建立一个账户并经过API或数据库预先配置独角兽。而后,您所要作的就是以用户身份登陆,找到Sparkles,并将其添加到购物车。
测试类型
TODO:添加关于验收测试,性能测试,负载测试,回归测试,测试驱动开发和/或行为驱动开发(JBehave,Capybara和Robot Framework)的段落,以及它们与Selenium的关系。
关于此文档
这些文档与代码自己同样,由Selenium社区内的志愿者维护100%。自从成立以来,许多人一直在使用它,可是还有不少人只是在短期内使用它,而且花时间帮助改善新用户的入职体验。
社区的许多成员在irc.freenode.net上频繁出现#selenium IRC频道。随意下载并提出问题,若是您得到了您认为能够在这些文档中使用的帮助,请务必添加您的贡献!咱们能够更新这些文档,可是当咱们从常规提交者以外得到贡献时,每一个人都会更容易。