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%。自从成立以来,许多人一直在使用它,但是还有很多人只是在短时间内使用它,并且花时间帮助改善新用户的入职体验。
如果文档存在问题,我们想知道!沟通问题的最佳方式是访问https://github.com/seleniumhq/docs/issues 并搜索以查看问题是否已经提交。如果没有,请随时打开一个!
社区的许多成员在irc.freenode.net上频繁出现#selenium IRC频道。随意下载并提出问题,如果您获得了您认为可以在这些文档中使用的帮助,请务必添加您的贡献!我们可以更新这些文档,但是当我们从常规提交者之外获得贡献时,每个人都会更容易。