Selenium

Installation

If you are using maven, you can add following dependency to your project.

01
02
03
04
05
<dependency>
    <groupId>org.unitils.selenium</groupId>
    <artifactId>unitils-selenium</artifactId>
    <version>1.0.8</version>
</dependency>

GUI testing

In this chapter we'll talk about automating tests for classic web application. When we talk about classic web application we mean html based applications, so no flash generated sites. The tests we're talking about are not unit tests but system tests. We'll test a whole system. And because the test runs against a gui, the html pages, we'll often use the word Gui tests. You could mock out the backend and just test the frontend but that is an effort we discourage you to do.

Two schools: There are mainly two different approaches to create automated Gui test.

  • You can use a tool to record and playback tests
  • You can program yourself an automated test using an automation api

The reason why there are two approaches is explained by the fact that there are mainly two types of people doing the job. You have functional people who understand the business and are best placed to define the testcases. Often they also execute the testcases to validate that the application acts as they expect. Recording and playback tools will help ease the task of test automation for these people. There are a lot of tools on the market, commercial and opensource. People with a technical background can choose another option: programming the automation scripts. This approach allows you to create much cleaner code. It will also force you to think of scriptcode reusage which will reduce script maintanance. In this chapter we'll defend this statement.

Record and Playback: Using a tool to record testcases will allow you to create a lot of scripts in a record period of time. In this power lays directly the danger. The more you create the more you have to maintain.

NOTE: You can download the selenium-ide add-on for Firefox. You can record some moves and than it will replay it. But even when you want to use the unitils-selenium module, it can be handy. When you go to options, then to clipboard format and if you select the option JUnit 4 (Webdriver) than you can copy paste all the commands into your eclipse and you will see that you already have the ids of the different components of your html page. This is one option, but there are other posibilities like firebug.

Domain Specific Language (DSL) You can use inheritance & composition to avoid code duplication and to limit the code to maintain to a minimum. You can create a base page with all the items in the header, that all other pages must extend.

Config

Please create unitils-local.properties, and add selenium to unitils.modules. Code as following:

01
02
03
04
05
06
07
08
09
10
unitils.modules = [... other modules ...], webDiver
 
unitils.module.webDriver.className=org.unitils.selenium.WebDriverModule
unitils.module.webDriver.runAfter=
unitils.module.webDriver.enabled=true
org.unitils.selenium.browser.name=FIREFOX
org.unitils.selenium.baseUrl= ???
# optional values: This is only needed when you want to download a file with Selenium.
org.unitils.selenium.downloadpath = ??? # (f.e.: C:\\Temp)
org.unitils.selenium.filetype= ???

browser: There are several browsers that you can choose from: Internet Explorer (IE), HtmlUnit(HTMLUNIT), firefox (FIREFOX), Chrome (CHROME).

file types: The default value for org.unitils.selenium.filetype: application/pdf, application/vnd.fdf, application/x-msdos-program, application/x-unknown-application-octet-stream, application/vnd.ms-powerpoint, application/excel, application/vnd.ms-publisher, application/x-unknown-message-rfc822, application/vnd.ms-excel, application/msword, application/x-mspublisher, application/x-tar, application/zip, application/x-gzip,application/x-stuffit,application/vnd.ms-works, application/powerpoint, application/rtf, application/postscript, application/x-gtar, video/quicktime, video/x-msvideo, video/mpeg, audio/x-wav, audio/x-midi, audio/x-aiff, application/octet-stream

How does a test work?
annotations:

BaseUrl You can define the base url in the unitils.properties or you can define it with this annotation.
TestWebDriver This annotation creates the driver. With the property "org.unitils.selenium.browser.name" in the unitils.properties file you define which browser you want to use for your tests. So if you define that you want to use firefox, than you get a FirefoxDriver.
WebPage The field with this annotation represents a web page. this means that it contains the webelements of a webpage.It uses the webdriver (field with @TestWebDriver) to initialize the elements.

Example

If the webpage has a menu, you should make a base page with all the menu items and all the pages extends this base page. If you know the id, path ... of the webelement, you can use the FindBy annotation. In this example there is a menu with a link to a search page and a create page.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class BasePage {
 
    @FindBy(id="navigationForm:menuCreate")
    private WebElement createElement;
 
 
    @FindBy(id="navigationForm:menuSearch")
    private WebElement searchElement;
 
    public void gotoCreate() {
        createElement.click();
 
    }
 
    public void gotoSearch() {
        searchElement.click();
    }
 
}

The Searchpage of the following example extends from the BasePage and contains all the important web elements of that specific webpage.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class SearchPage extends BasePage {
     
    @FindBy(id = "createForm:name")
    private WebElement surname;
     
    @FindBy(id = "createForm:firstName")
    private WebElement firstName;
     
    @FindBy(id = "createForm:tolerance")
    private WebElement tolerance;
     
    @FindBy(id = "createForm:birthdate")
    private WebElement birthDate;
     
    @FindBy(id = "createForm:searchButton")
    private WebElement searchButton;
     
     
    /**
     * @param surname the surname to set
     */
    public void setSurname(String surname) {
        this.surname.sendKeys(surname);
    }
     
    /**
     * @param firstName the firstName to set
     */
    public void setFirstName(String firstName) {
        this.firstName.sendKeys(firstName);
    }
     
     
    /**
     * @param tolerance the tolerance to set
     */
    public void setTolerance(String tolerance) {
        this.tolerance.sendKeys(tolerance);
    }
     
     
    /**
     * @param birthDate the birthDate to set
     */
    public void setBirthDate(Date birthDate) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(birthDate);
        this.birthDate.sendKeys(cal.get(Calendar.MONTH) + "/" + cal.get(Calendar.DATE) + cal.get(Calendar.YEAR));
    }
}

In the example the nameField and firstName are textboxes and it will put the correct string into the text box. The best way to create your tests, is creating a base web test class. In this class you can put your web driver and base URL.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@RunWith(UnitilsJUnit4TestClassRunner.class)
public class AbstractWebTest {
 
 
    @TestWebDriver
    private WebDriver driver;
 
    @BaseUrl
    private String baseUrl;
     
    public AbstractWebTest(){
    }
     
    public WebDriver getDriver() {
        return driver;
    }
 
     
    public String getBaseUrl() {
        return baseUrl;
    }
 
 
}

All your other tests have to extends this base test class, just like in the following example.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public class SearchScenarioTest extends AbstractWebTest {
 
    @Test
    public void test() throws InterruptedException {
        getDriver().get(getBaseUrl());
         
        SearchPage searchPage = PageFactory.initElements(getDriver(), SearchPage.class);
        //Thread.sleep(10000);
        searchPage.gotoCreate();
        searchPage.gotoSearch();
         
        //... Asserts...
    }
     
 
}

Creating screenshots

If a selenium test goes wrong than the framework creates automatically a new screenshot of the last screen before it kills the webdriver. If there is an @Testlink annotation on the test than he will create a screenshot with the Testlink id as name.

But if you want to make screenshots while selenium is running your test, than you can create a org.unitils.selenium.ScreenshotTakingWebDriver and call the method saveScreenshot().

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
@RunWith(UnitilsBlockJUnit4ClassRunner.class)
public class ScreenshotTakingWebdriverExampleTest {
     
    @BaseUrl
    private String baseUrl;
     
    @TestWebDriver
    private WebDriver webDriver;
 
    @Test
    public void testWithScreenshots() {
        ScreenshotTakingWebDriver screenshotWebdriver = new ScreenshotTakingWebDriver(webDriver, baseUrl);
        webDriver.get(baseUrl);
        screenshotWebdriver.saveScreenshot();
        webDriver.get("http://unitils.org/summary.html");
        screenshotWebdriver.saveScreenshot();
    }
}

The default location is under target/screenshot/[nameOfTheTest].
This is a nice feature for analists, they don't need to do stupid activities like taking screenshots anymore.

Drivers

Sometimes it's possible that you don't use the correct driver for your browser.
Than you get exceptions like f.e. 'The path to the driver executable must be set by the webdriver.ie.driver system property'.
You can find the correct driver on the internet:

  • IE drivers
  • Chrome drivers

    And you can simply add them with a Unitils property.

    01
    02
    03
    org.unitils.selenium.firefoxbinary= ? #location of the firefox driver
    org.unitils.selenium.chromedriver= ? #location of the chrome driver
    org.unitils.selenium.iebinary= ? #location of the ie driver

    The latest drivers are also added to unitils-selenium. If the WebdriverModule cannot find a property or a good driver in your system property than he will use that driver. \

    Note: You should always close the driver correctly, if you close the screen in the middle of a test, than he won't kill the driver correctly and than you must kill the driver with your taskmanager.

Chrome binary

If you've installed youre browsers with the installer, than youre browsers are on a fixed place and unitils-selenium hasn't got problems with finding the binary (.exe file on windows).

But if your browser is on a different location or if you use something like f.e. LiberKey, than you can set the location of the binary with the following property:

01
org.unitils.selenium.chromebinary = #location of the exe.

logging

You can print the selenium logging in a file or in the console.

01
02
03
04
05
06
07
08
org.unitils.selenium.logging.console.enabled=true #prints the console output after a test and before the @After method begins
org.unitils.selenium.logging.performance= ? #default: OFF
org.unitils.selenium.logging.browser= ? #default: OFF
org.unitils.selenium.logging.client= ? #default: OFF
org.unitils.selenium.logging.driver= ? #default: OFF
org.unitils.selenium.logging.profiler= ? #default: OFF
org.unitils.selenium.logging.server= ? #default: OFF
org.unitils.selenium.logging.file= ? #The output can also be printed in a file, if you give the location of the file.

Downloading files with Selenium

Downloading files with Selenium can be a little bit tricky.
For Firefox and Chrome it's quite easy... just add the download folder property in your unitils.properties and the files are downloaded in that folder. The filetype property can be set, but it is only needed if you want to download a specific type of file.

01
02
org.unitils.selenium.downloadpath = ??? # (f.e.: C:\\Temp)
org.unitils.selenium.filetype= ???

But if you want to test your application with Internet Explorer than it can be more difficult, because there appears a window that you can't get rid off. There are a few options, you can work with AutoIt or you can use a robot. We created a robot for downloading files with Internet Explorer 9. If you add the following property in your unitils.properties, than you only have to change the property if you change your Internet Explorer..

01
org.unitils.selenium.downloader.RobotDownloader = ????

The following example will try to download a file with IE, verifies if the file actually exists and deletes the file at the end of the test.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
@RunWith(UnitilsBlockJUnit4ClassRunner.class)
public class DownloadFileExampleTest {
    @TestWebDriver
    private WebDriver driver;
    private RobotDownloader robotDownloaderIE;
 
    @Before
    public void setUp() {
        robotDownloaderIE = RobotDownloaderFactory.createDownloaderIE();
    }
 
    @Test
    public void testDownloadFile() throws Exception {
 
        WebElement downloadLink = driver.findElement(By.linkText("spring-framework-ref..>"));
        robotDownloaderIE.clickAndSaveFileIE(downloadLink);
        robotDownloaderIE.checkIfDownloadedFileExists(downloadLink);
 
        robotDownloaderIE.deleteDownloadedFile(downloadLink);
    }
}

If you know the link and you only want to test how the file looks like, than you can check it another way.

01
02
03
04
05
06
07
08
@Test
public void testDownloadUrl() throws Exception {
 
    File tempFile = File.createTempFile("expectedTempFile", ".pdf");
    FileUtils.copyURLToFile(url, tempFile);
    Assert.assertTrue(tempFile.exists());
}

The files (downloaded with the RobotDownloader) are downloaded in the user downloads folder.