Internal and external quality metrics
Software has two quality metrics, external and internal quality. External quality is how well the system meets the needs of its customers and users (is it functional, reliable, available, responsive, etc.), and internal quality is how well it meets the needs of its developers and administrators (is it easy to understand, easy to change, etc.).
For measuring external quality, we have to write acceptance tests that test our system end-to-end. An end-to-end test interacts with the system only from the outside: through its user interface, by sending messages as if from third-party systems, by invoking its web services, by parsing reports, and so on. At ZeroTurnaround, we rely on Selenium for acceptance testing, so it was cool to find out a couple of months ago about Selenide (we suspect it’s pronounced as SEL-le-nide, rhymes with tide), which we now use for tests for UI activities in LiveRebel, our “bulletproof release tool”. Selenide is a concise and, as Codeborne engineers call it, expressive wrapper API specifically for Selenium WebDriver, which is used to control browser actions. So I thought I’d share a couple interesting/notable things about Selenide with you here.
An integral part of functional/acceptance UI test is selection of an element. You need to select an element to interact with it, check its state, wait for some condition to come true, etc. Selenide makes this as easy and fluent as possible.
Selenide offers following (jQuery-like) ways for selecting element/elements:
$(String cssSelector)– returns SelenideElement
$(By)– returns SelenideElement
$$(String cssSelector)– returns ElementsCollection
$$(By)– returns ElementsCollection
There are multiple useful static factory methods in the Selectors class for creating different
- byText – search by text (substring)
- withText – search by exact text string
- by – search by attribute
- byTitle – search by “title” attribute
- byValue – search by “value” attribute
As elements in the DOM are hierarchical, sometimes you may want to select some element that resides in another element. In this case, Selenide allows you to chain selecters.
For example, you can select some row from a table in the following way:
SelenideElement roundHouseRow = $(“.table”).$(byText(“Norris”));
Nowadays, many websites use AJAX to change some parts of the website dynamically, which means we need to wait for some conditions to come true when we test our application. For that purpose, Selenide has a Condition class. Unlike Selenium, Selenide waits for some predefined timeout for the given Condition to come true. By default, the timeout to wait for is 4 seconds, this is of course configurable (via
selenide.timeout property). Conditions are also used for testing that webpage has expected elements and that elements have the desired state.
Some out-of-the-box Conditions you can use:
- matchText(String text) – for matching substring
- text(String text) – for matching whole text
- not(Condition condition) – for negating condition
As Condition class is abstract, users can easily define new Conditions that one might need.
Here is a little example that checks that a query button is present and visible on the page and clicking on it produces expected result.
SelenideElement queryButton = $(“#query-button”); queryButton.shouldBe(present, visible); queryButton.click(); SelenideElement result = $(“#query-result”).waitUntil(present); result.shouldHave(text(“Chuck”));
From this example, we can also see that Selenide has put an effort into making all the statements as readable as possible, even by non-technical staff. +10 for that!
HTML has multiple constructs that consist of multiple elements, like tables with multiple rows, multiple options for a selected element, radio button groups, different kinds of lists and more. We might have multiple elements that have the same name, or we want to perform operations on all elements that have the same class. So we’ll need a construct that allows us to perform operations on multiple elements, and Selenide has handy ways to work with collections of elements: ElementsCollection.
You can perform following actions on collections of elements:
- shouldBe – e.g.
- shouldHave – e.g.
$$("#mytable tbody tr").shouldHave(size(2))
- find – e.g.
- filter – e.g.
- exclude – e.g.
From time to time, your tests are going to fail. That’s ok! For cases like this, we would like to have as much information as possible to quickly hunt down the reason of the failure. To help you figure out what happened, Selenide lets you take a snapshot of the browser window upon test failure, and screenshot of the webpage along with the HTML content is stored for your debugging pleasure. It’s also set up to use with JUnit and TestNG. Cool, right?
Using with JUnit runner
@Rule public final ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests();
Using with TestNG runner
Annotate your test class with
Custom browser capabilities
-Dbrowser parameter (Deprecated in Selenide 2.4), or passing the driver to
WebDriverRunner.setDriver (the currently-recommended way) before starting the test.
All seems pretty simple, right?
All in all, Selenide is really nice and capable tool for writing functional/acceptance tests for your browser-based UI. Its declarative style makes your tests readable and easily exposes their intent. Good readability of the tests is good quality to have, because your test are supposed to describe and document your application’s behavior. Writing tests using Selenide is easy as well, to quote authors of Selenide – “Just type:
$(selector). – and IDE suggests you all the options.” I encourage you to check Selenide out and give it a try. Leave comments below and let us know how it goes at @ZeroTurnaround.