End-to-end functional testing of WEB applications in multiple browsers
Selenium is a well-known WEB application Testing framework for functional testing. The new version Selenium 2 combines the best features in Selenium 1 and Webdriver (Selenium parallel projects). In this article, we'll show you how to easily transition from Selenium 1 to Selenium 2, and some examples of how to use Selenium 2, how to do remote testing, and how to migrate written tests from Selenium 1 to Selenium 2.
Brief introduction
Selenium is a common framework for testing the WEB application user interface (UI). It is an extremely powerful tool for running end-to-end functional testing. You can write tests in multiple programming languages, and Selenium can perform these tests in one or more browsers.
Selenium (hereinafter referred to as Selenium 1) is not the only tool that can automate functional testing in a browser. The webdriver created by Simon Stewart (from Google) is a project with similar goals. To control the browser, you need to rely on a standalone client with native support. Webdriver only provides Java bindings and does not support as many browsers as Selenium 1 can support.
Selenium 1 + webdriver = Selenium 2
Selenium 1 and Webdriver merged into a better performing product Selenium 2 (or Selenium webdriver), which was released in 2011. Selenium 2 has a clear object-oriented API from Webdriver and is able to interact with the browser in the best way possible. Selenium 2 does not use JavaScript sandboxing, it supports multiple browsers and multi-language bindings. At the time of this writing, Selenium 2 provides drivers for the following programs:
- Mozilla Firefox
- Google Chrome
- Microsoft Internet Explorer
- Opera
- Apple IPhone
- Android Browsers
With Selenium 2, you can write tests using Java, C #, Ruby, and Python. Selenium 2 also offers a htmlunit-based, headless driver, which is the Java framework for testing WEB applications. Htmlunit runs very fast, but it is not a real driver associated with a real browser.
Currently, Selenium 2 is still in the development phase, and some details are being addressed. The current version is 2.9. Drivers for Safari and Blackberry will be integrated into the product in the near future.
In this article, we'll learn how to test Web applications with Selenium. The example shows how to implement the test remotely. We will also learn how to transfer well-written tests from Selenium 1 to Selenium 2.
Download the source code used in this article.
Selenium 2 Getting Started
In this section, we will learn how to use the Selenium 2 framework for a relatively simple test of a WEB application. The development environment uses the Java language. You will also need to include the Java binding selenium-java-<version>.jar (see Resources and download). In a Maven project, you only need to include the correct dependencies in Pom.xml, as shown in Listing 1.
Listing 1. Selenium-java Dependency
<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId> selenium-java</artifactid> <version>2.9.0</version> </dependency>
Now, you can start writing tests. The main component in the Webdriver API is the WebDriver
interface. This common interface can be implemented in every valid browser. For example, the class FirefoxDriver
will be used to control Mozilla Firefox. Listing 2 shows how to instantiate a specific implementation in a test. You can use the test framework that best suits your needs, such as JUnit or TestNG.
Listing 2. Instantiation of
FirefoxDriver
public class Selenium2example1test { @Test public void Test () { //instantiate a webdriver implementation< C10/>webdriver webdriver = new Firefoxdriver (); } }
To load a page for testing, you can use the get()
method. In Listing 3, the GitHub Master (https://github.com) is loaded into the previously created Firefox instance.
Listing 3. Load the page under test
Webdriver Webdriver = new Firefoxdriver (); Webdriver.get (https://github.com);
You can add assertions on the page you just loaded. If you want to test whether the page title is equal "GitHub - Social Coding"
, the following is shown in Listing 4. Webdriver provides getTitle()
methods that you can use to generate assertions using the selected test framework.
Listing 4. Assertion of page title
Assert.assertequals ("Github-social Coding", Webdriver.gettitle ());
After the test is complete, it is best to use the quit()
method to terminate the Webdriver instance, as shown in Listing 5.
Listing 5. Terminating Webdriver Instances
Webdriver.quit ();
FirefoxDriver
Just one of the effective webdriver implementations. You can use Chromedrive to run tests inside Chrome to perform the same tests. Listing 6 shows a complete example of leveraging Chromedriver.
Listing 6. Chromedriver Sample Example
public class Selenium2example2test { @Test public void Test () { System.setproperty (" Webdriver.chrome.driver "," Src/main/resources/drivers/chrome/chromedriver-mac "); Instantiate a Webdriver implementation webdriver Webdriver = new Chromedriver (); Webdriver.get (https://github.com); Assert.assertequals ("Github-social Coding", Webdriver.gettitle ()); } }
Before instantiating the chromedriver, you need to set the "webdriver.chrome.driver"
system properties correctly. This attribute indicates the location of the Chromedriver file for your operating system (see Resources and download). The example in Listing 6 uses the version for Mac, which is also available for Windows and Linux versions.
To perform the same test in Internet Explorer, you need to use InterentExplorerDriver
an instance of the class, as shown in Listing 7.
Listing 7.
InternetExplorerDriver
Instantiation of
Webdriver Webdriver = new Internetexplorerdriver ();
When used InterenetExplorerDriver
, you may encounter a security problem tip: "Protected Mode must be set to the same value (enabled or disabled) for all zones". To solve this problem, you need to set specific features, as shown in Listing 8.
Listing 8. Setting security features for Internet Explorer
Desiredcapabilities capability=desiredcapabilities.internetexplorer (); Capability.setcapability ( internetexplorerdriver.introduce_flakiness_by_ ignoring_security_domains, true); Webdriver Webdriver = new Internetexplorerdriver (capability);
To perform the test in opera, you need to instantiate the OperaDriver
class, which was developed directly by opera. Remember to include the driver's JAR in the project. If you use Maven, you only need to increase the dependencies in Listing 9.
Listing 9.
OperaDriver
Dependence
<dependency> <groupId>com.opera</groupId> <artifactid>operadriver</ artifactid> <version>0.7.3</version> </dependency>
Additional configuration is required for running tests in the IPhone or Android browser simulator.
Test with Selenium 2
Using Selenium 2, you can build tests that are more complex than the previous section. In this section, you will test to the top navigation of the GitHub home page with a total of 5 list items: Signup and Pricing, Explore GitHub, Features, Blog, and Login. Figure 1 shows the Github home page.
Figure 1. Github Home
View the HTML code for the top navigation, as shown in Listing 10.
Listing 10. HTML Code for top navigation
You can use the Webdriver API (from within the HTML code) to retrieve the elements you need to test. findElement()
and findElements()
methods return WebElement
An instance of the public interface or a set of instances. WebElement
can be applied to all elements in a page in a clear, object-oriented manner. There are many different strategies that can be used in the API to locate UI elements. These policies findElement()
findElements()
are represented by different types of parameters passed to and to the method. Listing 11 shows an example of applying the By
various methods of an abstract class to implement different policies.
Listing 11. UsefindElement()
MethodWebelement element1 = webdriver.findelement (By.id ("header")); Webelement Element2 = webdriver.findelement (By.name ("name")); Webelement Element3 = webdriver.findelement (By.tagname ("a")); Webelement element4 = webdriver.findelement (By.xpath ("//a[@title = ' logo ']"); Webelement element5 = webdriver.findelement (By.cssselector (". Feautures")); Webelement element6 = webdriver.findelement (By.linktext ("Blog")); Webelement element7 = webdriver.findelement (By.partiallinktext ("Ruby")); Webelement element8 = webdriver.findelement (by.classname ("login"));
Using one of the policies in Listing 11, you can begin writing tests to retrieve the first element: Tags UL
LI
with classes in markup nav
. Listing 12 uses Xpath ( By.xpath()
).
Listing 12. XpathList<webelement> webelements = webdriver.findelements (by . XPath ("//ul[@class = ' nav logged_out ']/li"));
Listing 13 uses the CSS selector ( By.cssSelector()
) to retrieve the LI
markup.
Listing 13. CSS SelectorList<webelement> webelements = webdriver.findelements (by . Cssselector ("Ul.nav li"));
At this point, an assertion can be generated on the number of items retrieved, as shown in Listing 14.
Listing 14. Assertion on number of itemsAssert.assertequals (5, Webelements.size ());
The previous steps verify that the LI
number of tokens equals 5.
The next step is LI
to retrieve each anchor point (marker) in each tag A
. Listing 15 shows how to get the anchor point in the first one LI
. This use case uses the TagName ( By.tagName()
) policy.
Listing 15. Retrieves the firstLI 标记
In theA
Anchor PointWebelement Anchor1 = webelements.get (0). Findelement (By.tagname ("a"));
You can use a similar method to collect all 5 anchor points, as shown in Listing 16.
Listing 16. RetrievalLI
All anchor points in the tagWebelement Anchor1 = webelements.get (0). Findelement (By.tagname ("a")); Webelement Anchor2 = webelements.get (1). Findelement (By.tagname ("a")); Webelement Anchor3 = Webelements.get (2). Findelement (By.tagname ("a")); Webelement Anchor4 = Webelements.get (3). Findelement (By.tagname ("a")); Webelement Anchor5 = Webelements.get (4). Findelement (By.tagname ("a"));
At this stage, you can verify that the text within the anchor point is consistent with the expected string. To retrieve the text within a tag, Webdriver provides a getText()
method. Listing 17 shows the complete test method and the assertion at the bottom of the test.
Listing 17. Complete the test @Test public void Test () {Webdriver webdriver = new Firefoxdriver (); Webdriver.get ("https://github.com"); List<webelement> webelements = Webdriver.findelements (by. XPath ("//ul[@class = ' nav logged_out ']/li")) ; Assert.assertequals (5, Webelements.size ()); Retrieve the anchors Webelement anchor1 = webelements.get (0). Findelement (By.tagname ("a")); Webelement Anchor2 = webelements.get (1). Findelement (By.tagname ("a")); Webelement Anchor3 = Webelements.get (2). Findelement (By.tagname ("a")); Webelement Anchor4 = Webelements.get (3). Findelement (By.tagname ("a")); Webelement Anchor5 = Webelements.get (4). Findelement (By.tagname ("a")); Assertions Assert.assertequals ("Signup and Pricing", Anchor1.gettext ()); Assert.assertequals ("Explore GitHub", Anchor2.gettext ()); Assert.assertequals ("Features", Anchor3.gettext ()); Assert.assertequals ("Blog", Anchor4.gettext ()); Assert.assertequals ("Login", Anchor5.gettext ()); Webdriver.quit (); }
When this test is started, a new Firefox window will open, and the window will remain open until all assertions are executed.
Using Selenium Grid 2 for remote testingLocal or remote testing can be done in Selenium 2. For remote runs, the test requires a RemoteWebDriver
WebDriver
specific implementation of the interface named. You can specify that the browser run as a DesiredCapabilities
class. Listing 18 shows the relevant examples.
Listing 18.RemoteWebDriver
AndDesiredCapabilities
ClassDesiredcapabilities capabilities = new Desiredcapabilities (); Capabilities.setbrowsername ("Firefox"); Capabilities.setversion ("7"); Capabilities.setplatform ("MAC"); Webdriver Webdriver = new Remotewebdriver (capabilities);
With DesiredCapabilities
classes, you can specify the browser's name, platform, and browser version. You can also specify additional features that your browser supports.
If you want to perform structured tests remotely and run multiple browsers (and possibly different virtual machines), the Selenium Grid provides a good solution.
Selenium Grid 2 provides the infrastructure, where each node represents a different browser to register itself with the hub. The singular test will call a hub, which is responsible for assigning each request to the correct browser. Hubs and nodes can be run in different virtual machines.
To implement a remote test, you need to download the Selenium-server-standalone-<version>.jar on each machine you will be using. To install the hub on the machine, go to the folder where you downloaded the JAR and run the command in Listing 19.
Listing 19. Start hubJava-jar Selenium-server-standalone-2.9.0.jar? Role hub
You can access the Grid 2 console in Http://localhost:4444/grid/console, which lists all available nodes. To register a node, you only need to run one command, as shown in Listing 20.
Listing 20. Nodes registered in the hubJava-jar Selenium-server-standalone-2.9.0.jar -role webdriver Hub Http://localhost:4444/grid/register-port 5556
By default, the command in Listing 20 registers 7 browsers: 5 Firefox instances, 1 Chrome instances, and an Internet Explorer instance. You can locate a specific browser on a specific port, as shown in Listing 21.
Listing 21. Firefox 7 instance registered on hubJava-jar selenium-server-standalone-2.9.0.jar-role webdriver -hub http://localhost:4444/grid/register-port 5556-browser Browsername=chrome,version=14,platform=mac
After registering some browsers, the Selenium Grid 2 console becomes as shown in Figure 2.
Figure 2. Selenium Grid 2 Console viewTo use the grid, you need to specify the hub's URL and the browser you want to control in the test case. Listing 22 shows that the RemoteWebDriver
class constructor accepts the hub's URL and defines an instance of a particular browser DesiredCapabilities
.
Listing 22.RemoteWebDriver
Instantiation ofDesiredcapabilities capability = new Desiredcapabilities (); Capability.setbrowsername ("Chrome"); Capability.setversion ("+"); Capability.setplatform (PLATFORM.MAC); Webdriver Webdriver = new Remotewebdriver (New URL ("Http://localhost:4444/wd/hub"), capability);
In this use case, the hub will launch the node associated with Chrome version 14 (previously registered in Listing 21).
The Selenium Grid 2 is also backwards compatible with Selenium 1. You can register the Selenium 1 RC node in the hub (which is part of the Selenium 1 infrastructure in the hub), as shown in Listing 23.
Listing 23. Selenium 1 RC Node RegistrationJava? jar Selenium-server-standalone-2.9.0.jar -role RC. Hub Http://localhost:4444/grid/register-port 5557
Migrating Tests from Selenium 1 to Selenium 2If you need to transfer the well-written tests from Selenium 1 to Selenium 2, the transfer will be fairly smooth. The Selenium 1 API remains in the new API, enabling Selenium 2 to be fully backwards compatible.
Transferring the test from Selenium 1 to Selenium 2 is very simple, thanks to the WebDriverBackedSelenium
class. It takes an WebDriver
instance and a URL as a test parameter, and returns a Selenium instance. Listing 24 shows the same example as in Listing 16, but uses the Selenium 1 API integrated into Selenium 2.
Listing 24. Set Selenium 1 to Selenium 2 @Test public void Test () {String URL = "Https://github.com"; Webdriver Webdriver = new Firefoxdriver (); Webdriver.get (URL); Selenium Selenium = new Webdriverbackedselenium (webdriver, URL); Selenium.open (URL); Get the number of lis number lis = Selenium.getxpathcount ("//ul[@class = ' nav logged_out ']/li"); Assert.assertequals (5, Lis.intvalue ()); Retrieve the text inside the anchors String anchor1text = Selenium.gettext ("//ul[@class = ' nav logged_out ']/li[1]/a ') ; String Anchor2text = Selenium.gettext ("//ul[@class = ' nav logged_out ']/li[2]/a"); String Anchor3text = Selenium.gettext ("//ul[@class = ' nav logged_out ']/li[3]/a"); String Anchor4text = Selenium.gettext ("//ul[@class = ' nav logged_out ']/li[4]/a"); String Anchor5text = Selenium.gettext ("//ul[@class = ' nav logged_out ']/li[5]/a"); Assert.assertequals ("Signup and Pricing", anchor1text); Assert.assertequals ("Explore GitHub", anchor2text); Assert.assertequals ("Features", Anchor3text); Assert.assertequals ("Blog", Anchor4text); Assert.assertequals ("Login", Anchor5text); Webdriver.quit (); }
Selenium 2 more focused on developers. It has an API that is clearer than Selenium 1, getText()
as getXpathCount()
evidenced by the method signature. The Selenium 2 API also has better object-oriented features. For example, you are not allowed to work with UI element objects and only allow strings to be processed.
ConclusionSelenium 2 marks an evolutionary process of automated testing within the browser. It inherits the best parts of Selenium 1 and Webdriver, and provides tight integration with multiple browsers. The new API is more in line with developer requirements, provides an object-oriented approach, and provides different models for writing tests. In addition, Selenium 2 also:
- Overcome the restrictions associated with the same original policy.
- Provides better support for pop-up windows.
- Control the keyboard and mouse interaction of the machine effectively.
The new version of the Selenium Grid (included in Selenium 2) makes it easier to load tests remotely. The Selenium 2 is backwards compatible with Selenium 1, so it's easy to upgrade to a new version. Selenium 2 can help ensure that your application works as needed.
Selenium 2 Getting Started