4.2 Object Oriented UI Testing Patterns
4.2.1 Page Objects
Its main objective is to model Web page areas into objects to reduce the amount of the duplicated code and also to enhance the tests main- tainability [37].
The key principles used to achieve this and best practices for working with Page Objects are [37]:
• the HTML structure of the page is defined only in one place - so that the change in the HTML code will affect tests as little as possible
• Page Objects expose services to developers, in other words provide methods to interact with page
• these methods should again return other Page Objects - this encourages test developers to interact rather with the services than with the implementation. As a result they are able to control which tests will fail. Easily said, it means better maintainability • Page Objects do not have to represent whole web site, they can
An example of such Page Object can be the online translate service (Google Translate5) provided by Google Inc.
The primary service it provides is of course translating from one language to another. But to do so, user often need to choose both from and to which language to translate particular word.
Programmatically speaking, implementing the Page Object for such a Web page using the WebDriver can be written as the code snippet 4.3. The connection between this code and the Google Translate page is represented in a more comprehensive way in figure 4.2.
Figure 4.2: Screenshot of Google Translate page (20th April 2012) with references to the code lines from 4.3.
1 public c l a s s G o o g l e T r a n s l a t e { 2
3 @FindBy ( xpath = " // i n p u t [ @type=’ submit ’ ] ") 4 private WebElement t r a n s l a t e B u t t o n ;
5
6 @FindBy ( xpath=" // t e x t a r e a [ @id=’ s o u r c e ’ ] ") 7 private WebElement i n p u t A r e a ;
8
9 @FindBy ( xpath=" // span [ @id=’ r e s u l t _ b o x ’ ] ") 10 private WebElement r e s u l t A r e a ; 11 12 public S t r i n g t r a n s l a t e ( S t r i n g word ) { 13 i n p u t A r e a . sendKeys ( word ) ; 14 t r a n s l a t e B u t t o n . c l i c k ( ) ; 15
16 (new WebDriverWait ( webDriver , 4 ) ) . u n t i l (new
E x p e c t e d C o n d i t i o n <Boolean >() { 17 18 public B o o l e a n a p p l y ( WebDriver d ) { 19 return ( r e s u l t A r e a . g e t T e x t ( ) . t r i m ( ) . l e n g t h ( ) > 0 ) ; 20 } 21 } ) ; 22 23 return r e s u l t A r e a . g e t T e x t ( ) . t r i m ( ) ; 24 } 25
26 public void s e l e c t L a n g u a g e T o T r a n s l a t e T o ( Language
l a n g u a g e ) {
27 // implemented i n t h e s i m i l a r way
28 }
29
30 public void s e l e c t L a n g u a g e T o T r a n s l a t e F r o m ( Language
l a n g u a g e ) {
31 // implemented i n t h e s i m i l a r way
32 }
33 }
Listing 4.3: Google Translate - example of Page Object written in Java programming language.
As it is in accordance with the best practices this Page Object can be used in the functional test of the translating service as demonstrated by the code snippet.
What was meant by best practices is that only the GoogleTranslate object distinguishes the HTML structure of the real web page. Better said, it holds this information in WebElement objects - e.g. it knows that the translated result area has id set to result_box value. This Page Object can be used in the functional test of the translate service as demonstrates the code snippet.4.46
Let’s suppose that you want to use interaction with the Google
Translate in other test scenarios, or rather in other test methods, classes or even projects. Then imagine that the Translate button will be removed, and the translation will be triggered automatically, during filling in the input the particular word by releasing the key.
The above mentioned does not have to be just artificial change scenario. This can be easily done later for rendering that page on mobile devices, as the automated translation has already been implemented. Furthermore, it is needed to render as few items on mobile devices as possible.7
Then the only place which will need to be changed will be the Page Object, all dependent test classes will remain untouched. Hereby we reach the goal, enhancing tests maintainability.
1 public c l a s s T e s t G o o g l e T r a n s l a t e extends A r q u i l l i a n { 2 3 @Page 4 private G o o g l e T r a n s l a t e g o o g l e T r a n s l a t e ; 5 6 @Drone
7 WebDriver webD river ; 8 9 @Test 10 public void t e s t T r a n s l a t e W o r d ( ) { 11 g o o g l e T r a n s l a t e . s e l e c t L a n g u a g e T o T r a n s l a t e F r o m (new Language (" s k ") ) ; 12 g o o g l e T r a n s l a t e . s e l e c t L a n g u a g e T o T r a n s l a t e T o (new Language (" en ") ) ; 13 14 S t r i n g w o r d T o T r a n s l a t e = " ryba "; 15 S t r i n g e x p e c t e d T r a n s l a t i o n = " f i s h "; 16 17 S t r i n g a c t u a l T r a n s l a t i o n = g o o g l e T r a n s l a t e . t r a n s l a t e ( wordToTranslate , webDriver ) ; 18
7. The reason is obvious, as mobile devices have smaller screens, mobile application developers need to save space as well as size of requested data.
19 a s s e r t E q u a l s ( a c t u a l T r a n s l a t i o n , e x p e c t e d T r a n s l a t i o n ,
" The word was t r a n s l a t e d i n c o r r e c t l y ! ") ;
20 }
21 22 }
Listing 4.4: Example of the Arquillian functional test of the Google Translate page, written in the Java language.
In the abstract model created for this thesis, Page Objects are supported as demonstrated on lines 3 and 4 in figure 4.4. Note the differences between default WebDriver project and created model.
Prior to the usage of the particular Page Object, this object needs to be initialised properly. It means that all WebElements of that Page Ob- ject (lines 4, 7, 10 in code snippet 4.3) need to be initialised with a proper object so that they would not encounter NullPointerException.8
As opposed to WebDriver project, this initialisation is done with use of a factory method. We have implemented Page Java annotation(line 3 in code snippet 4.4) which will be recognized in the runtime by Drone extension and initialized with particular Page Object. Further information about integration with this extension is described in section 4.3.2.
4.2.2 Component Objects
Another pattern, or better said good OO (Object Oriented) approach to design reusable code is Component Object. It is very similar to the Page Objects. It also indentifies parts of the Web page and its services, however in a finer grained way. The objective of this is to provide components which are highly reusable. This pattern will be used mainly for creation of the API, its consequences are particular components.
It is based on Component-Based Architectural Style. This style provides a higher level of abstraction by decomposing of the design into logical or individual components that expose well-defined interfaces containing methods, events, and properties.
Components designed in this style should follow following principles [38]:
• Reusable - they should be designed in a way to be easily reused in other parts of the same or different application;
• Replaceable - components should be easily replaced by other components;
• Not context specific - the state should not be included into components, it should be passed to them;
• Extensible - to provide a new behaviour, a component should be easily extended;
• Encapsulated - basic OO rule that methods should not expose the internal implementation, variables or state;
• Independent - in order to use components in other environments, there should be minimal number of the component’s dependen- cies.
Abstract component model implemented for this thesis are trying to meet this requirements. Components are reusable across all projects, they are defined in the Java, but the implementation can describe any component-based Web framework. 4.1.1 They can be easily added to your project as Apache Maven.
One implementation of the component can be replaced by another. This is achieved by defining at first common interface for that component. Then, with regards to the another OO design principle, program to an interface, not an implementation [39], the component dependency can be replaced by the other component, as the second component also implements the common interface.
The interfaces for components do not contain state, however, the implementation does. This is the specific of the component-based frame- works. The framework that the HTML code generated for the particular component is the same for all applications. More information about this specific can be found at the section 4.1.1. Another state which needs to be accessible for components, is which browser they are rendered on. However, this information is injected into them in runtime by Ar- quillian DI (Dependency Injection) mechanism, so it is not wired with components.
The implemented components are also extensible, because the imple- mentation classes are non final and define public constructors, or to be more precise they do not define private constructors. The new behaviour can be then added by the standard extension Java mechanism. It is then on the developer, whether his components will be extendable or not, but the standard ones, from the abstract model are.
Components are encapsulated by encapsulating all the methods, in other words, the Javadoc9 and the names of the methods are not
exposing how their service is done, which means that the particular implementation is hidden.
Let’s take the Google Translate Web page into consideration one more time. This time the whole page will be divided into smaller parts.
Figure 4.3: Google Translate Web page screenshot (20th April 2012) with components identified.
Several components can be identified in the Web page from figure4.2. These components can be used in other pages. Among the simple components we can see following: button, select and text area, continuing with more complex like tab panel or virtual keyboard. The figure 4.3 shows a graphical representation of those.
9. Javadoc - way of creating documentation for Java methods, classes and other structures.