Web application integration testing with Selenium WebDriver

    Integration testing (as opposed to Unit- or unit testing) is not testing individual atomic components of a system (classes), but the result of their interaction with each other in any environment.

    By the will of fate, I am developing a kind of interface framework tailored for certain corporate needs. The framework runtime is a browser, and therefore the language is JavaScript.

    About how I can Unit-test JavaScript, I wrote earlier , now I’ll talk about the integration testing process used in the team.

    Selenium


    For a long time known tool for testing web applications / pages in a browser - Selenium . In terms of its application, there are two main ways, namely:
    1. writing TestSuite in SeleniumIDE and running them through SeleniumTestRunner, or
    2. using webriver

    WebDriver is a new Selenium "feature" that appeared in the second branch of the product. Its main essence is that you can run the tests described in the code (C #, Java, Python, Ruby), in different browsers and / or in the virtual runtime.

    Webriver


    Selenium WebDriver is a set of “binders” for different languages ​​(C #, Java), allowing you to give various commands to a “subordinate” browser.

    Each browser has its own implementation of WebDriver (FireFoxDriver, InternetExplorerDriver, ChromeDriver - now included in the package, OperaSoftware developed OperaDriver ). There is also a “virtual” HtmlUnitDriver. Unlike “browser” implementations, it does not require an installed browser and due to this it works faster and platform independent, but there are also disadvantages - HtmlUnitDriver has “its own” JavaScript implementation and therefore the behavior of “rich” web applications may differ in it. For our tasks, we use “browser” implementations, this allows us to test the application in the exact environment in which it will be executed later.

    Briefly, the general essence of working with WebDriver can be described as follows:
    • code is implemented using any WebDriver implementation. This code performs any actions on the web page and compares the result with the reference
    • WebDriver translates commands to a running browser (when using a "browser" implementation) and reports the results "back to code"

    What WebDriver can do


    The following is a “browser” implementation, the essence of the extension is the RemoteWebDriver class (implements the WebDriver interface).
    • element search: findElement (s) By *
      • Cssselector
      • Classname
      • Id
      • Linktext
      • Tagname
      • XPath
    • page loading, getting page content
    • execution of arbitrary javascript
    • Drag-n-Drop operations

    With "found" elements (WebElement interface)
    • receiving text (text)
    • getting value
    • click on an element
    • keyboard input (key, keyboard shortcut, sequence of keys / keyboard shortcuts)

    Test runtime


    As a language for writing tests, Java was chosen. The runtime is JUnit4 .

    DISCLAIMER : I do not pretend to be a cool javist, so if senior colleagues find flaws and all sorts of other “antipatterns”, I will listen with pleasure in the comments.

    Basic abstract web test class.
    @Ignore
    abstract public class AbstractWebTest {
        protected static RemoteWebDriver _driver;
        // расположение тестовой страницы
        private String testPageLocation =
                    String.format(
                            "http://%s:%s/test.html",
                            System.getProperty("test.httproot"),         // Web-сервер ...
                            System.getProperty("test.httpport", "80")   // и порт
                    );
        // Используемая имплементация WebDriver
        private static String driverName =
                    System.getProperty(
                            "test.driver",
                            "org.openqa.selenium.firefox.FirefoxDriver");
        /**
         * Перед каждым набором тестов - создаем инстанс драйвера.
         * Это автоматически запустит браузер
         */
        @BeforeClass
        public static void setUpDriver()
                    throws ClassNotFoundException,
                              IllegalAccessException,
                              InstantiationException {
            _driver = (RemoteWebDriver) Class.forName(driverName).newInstance();
        }
        /**
         * Перед каждым тестом - открываем тестовую страницу
         */
        @Before
        public void setUp() {
            _driver.get(testPageLocation);
        }
        /**
         * После каждого набора тестов - закрываем инстанс дарйвера (закрываем браузер)
         */
        @AfterClass
        public static void tearDown() {
            _driver.close();
        }
    }

    A specific class with a set of tests (for simplicity, some checks have been removed, for example, that an element by CSS selector is indeed found and available on the page)
    public class TestMoneyField extends AbstractWebTest {
        /**
         * При рендеринге поле ввода денежной суммы должно показать 0.00
         */
        @Test
        public void testRendering() {
            WebElement content =
               _driver.findElementByCssSelector("#FieldMoney .input-text-field");
            Assert.assertEquals("0.00", content.getValue());
        }
        /**
         * Проверим форматирование "триад"
         */
        @Test
        public void testInputWithoutDot() {
            WebElement content =
               _driver.findElementByCssSelector("#FieldMoney .input-text-field");
            content.sendKeys("999999");
            Assert.assertEquals("999 999.00", content.getValue());
        }
    }

    All tests are run using a separate Ant build:

    This task will run all known tests from classes whose names begin with Test under Firefox and InternetExplorer. In the dependencies are tasks with basic initialization, compilation and unloading of compiled tests to the test site.

    Bun Chips


    Some "browser" implementations (Firefox, Opera, Chrome) support taking screenshots. This can be useful in order to fix the visual state in which the test page was at the moment when the test failed. Functionality JUnit4 - TestWatchman is suitable for this .
    @Ignore
    abstract public class AbstractWebTest {
        // Папка для скриншотов
        private String screenshotDir =
                System.getProperty("test.screenshotDir", "");
        @Rule
        public MethodRule watchman = new TestWatchman() {
            /**
             * Будет вызван при каждом "проваленном" тесте
             * @param e Брошенное тестом исключение
             * @param method Тест-метод
             */
            @Override
            public void failed(Throwable e, FrameworkMethod method) {
                if(_driver instanceof TakesScreenshot && !screenshotDir.equals("")) {
                    String browserName = _driver.getClass().getName();
                    String testSuiteName = method.getMethod().getDeclaringClass().getName();
                    browserName =
                            browserName.substring(browserName.lastIndexOf('.') + 1);
                    testSuiteName =
                            testSuiteName.substring(testSuiteName.lastIndexOf('.') + 1);
                    byte[] screenshot =
                            ((TakesScreenshot)_driver).getScreenshotAs(OutputType.BYTES);
                    try {
                        FileOutputStream stream =
                                new FileOutputStream(
                                        new File(
                                            String.format("%s/screenshot_%s_%s_%s.png",
                                                    screenshotDir,
                                                    browserName,
                                                    testSuiteName,
                                                    method.getName())));
                        stream.write(screenshot);
                        stream.close();
                    } catch (IOException e1) {
                        e1.printStackTrace(System.out);
                    }
                }
            }
        };
        // все остальное...
    }

    Add the variable with the path to the folder with screenshots to the Ant build

    Integration


    In the current implementation, the Ant build is chased through Jetbrains TeamCity . The build launch is configured to reset the code in SVN. Integration tests are part of the overall testing procedure. If any of the integration tests fails, a screenshot is taken and published as an “artifact” of the build - you can see not only which tests “left” after resetting any functionality to the trunk, but also see “how” they “left”.

    Currently testing under IE and Firefox is used, Chrome is not connected due to some difficulties with integration (apparently there are some errors in ChromeDriver that do not allow you to normally search for elements on the page in some cases - as of 2.0b1, now 2.0b2 is available but we haven’t tried working with it yet)

    Also popular now: