Automated Testing of The Component-Based Web Application User Interfaces
Automated Testing of The Component-Based Web Application User Interfaces
/012345<yA|
Masaryk University
Faculty of Informatics
Bachelor thesis
Juraj Húska
Brno, 2012
Declaration
Hereby I declare, that this paper is my original authorial work, which
I have worked out by my own. All sources, references and literature
used or excerpted during elaboration of this work are properly cited
and listed in complete reference to the due source.
Juraj Húska
ii
Acknowledgement
I would like to thank RNDr. Petr Ročkai, the advisor of my thesis,
for his help, comments and time spent helping me with this work.
I am profoundly grateful to Bc. Lukáš Fryč for his guidance and
support throughout my work.
I would like to also thank Mgr. Marek Grác for his advices. My thanks
go to my parents, my girlfriend and my close friends as well.
iii
Abstract
This bachelor thesis explores and describes modern trends in testing
enterprise web applications. After the investigation, tools for automated
testing of these applications are selected and compared according to
maintainability, implementation of these tests and their usage in the
systems of continuous integration. Based on the analysis, a high level
application programming interface for using in testing the component
based web application user interfaces is implemented.
iv
Keywords
software testing, abstract component model, high-level API, Web UI
testing
v
Contents
1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2 Testing of enterprise web applications . . . . . . . . . . 3
2.1 Definition of testing . . . . . . . . . . . . . . . . . . . . . 3
2.2 Division of testing . . . . . . . . . . . . . . . . . . . . . . 3
2.2.1 According to way testing is performed . . . . . . 3
Manual testing . . . . . . . . . . . . . . . . . . . 3
Automated testing . . . . . . . . . . . . . . . . . 4
Benefits and drawbacks of both approaches . . . 4
2.2.2 According to depth . . . . . . . . . . . . . . . . . 6
White-box testing . . . . . . . . . . . . . . . . . 6
Black-box testing . . . . . . . . . . . . . . . . . . 6
Gray-box testing . . . . . . . . . . . . . . . . . . 6
2.2.3 According to scope . . . . . . . . . . . . . . . . . 7
Unit testing . . . . . . . . . . . . . . . . . . . . . 7
Integration testing . . . . . . . . . . . . . . . . . 12
System testing . . . . . . . . . . . . . . . . . . . 14
2.3 Continuous integration . . . . . . . . . . . . . . . . . . . 17
2.3.1 Key principles . . . . . . . . . . . . . . . . . . . . 17
2.3.2 Problems . . . . . . . . . . . . . . . . . . . . . . 18
2.4 Enterprise applications definition . . . . . . . . . . . . . 19
2.5 Enterprise testing approaches . . . . . . . . . . . . . . . 20
2.5.1 Other employed forms of testing . . . . . . . . . . 20
2.5.2 Example of enterprise testing process . . . . . . . 21
3 Evaluation of the tools . . . . . . . . . . . . . . . . . . . . 23
3.1 Criteria for choosing the tools examples . . . . . . . . . . 23
3.2 Selected tools . . . . . . . . . . . . . . . . . . . . . . . . 23
3.2.1 Arquillian Drone . . . . . . . . . . . . . . . . . . 24
3.2.2 Geb . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.3 The results . . . . . . . . . . . . . . . . . . . . . . . . . 27
4 Component Model . . . . . . . . . . . . . . . . . . . . . . . 28
4.1 Motivation for creating the component model . . . . . . 28
4.1.1 Component based Web frameworks . . . . . . . . 30
4.1.2 Model requirements . . . . . . . . . . . . . . . . . 31
4.2 Object Oriented UI Testing Patterns . . . . . . . . . . . 32
4.2.1 Page Objects . . . . . . . . . . . . . . . . . . . . 32
vi
4.2.2 Component Objects . . . . . . . . . . . . . . . . . 36
4.3 Implementing the Component Model . . . . . . . . . . . 38
4.3.1 Employed Java technologies . . . . . . . . . . . . 39
Java Reflection . . . . . . . . . . . . . . . . . . . 39
Java Dynamic Proxies . . . . . . . . . . . . . . . 41
Java Generics . . . . . . . . . . . . . . . . . . . . 43
Service Provider Interface . . . . . . . . . . . . . 45
4.3.2 Integration with existing Frameworks . . . . . . . 45
WebDriver . . . . . . . . . . . . . . . . . . . . . 45
Arquillian Drone . . . . . . . . . . . . . . . . . . 48
4.4 Component Case Studies . . . . . . . . . . . . . . . . . . 52
4.4.1 Autocomplete component . . . . . . . . . . . . . 53
4.4.2 Table component . . . . . . . . . . . . . . . . . . 55
4.4.3 Calendar component . . . . . . . . . . . . . . . . 58
4.5 Real Deployment . . . . . . . . . . . . . . . . . . . . . . 60
4.5.1 Showcase application . . . . . . . . . . . . . . . . 60
4.5.2 Functional Tests . . . . . . . . . . . . . . . . . . 61
5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
A Example of UI test verbosity . . . . . . . . . . . . . . . . 70
B Factory class and its methods . . . . . . . . . . . . . . . . 71
C Test enricher . . . . . . . . . . . . . . . . . . . . . . . . . . 73
D Sequence Diagram of Autocomplete Component . . . . 74
E Sequence diagram of Table Component . . . . . . . . . . 75
F Sequence Diagram of Calendar Popup Component . . 76
G Omitted Arquillian test configuration. . . . . . . . . . . 77
H Manual for building showcase application . . . . . . . . 78
I Functional test without using of Component Model . . 79
J Functional test with using of Component Model . . . . 82
K Contents of Attached CD . . . . . . . . . . . . . . . . . . 84
vii
1 Introduction
Testing software is an important part of development of all applications.
For enterprise applications, however, it is inevitable. This is due the
fact that a development of enterprise applications is costly and time-
consuming, but carefully choosing improved testing methods leads to
cheaper development and maintenance [1].
At present time, an increasing number of applications, either en-
terprise or standard, is focusing on running in browsers, on desktops
and mobile devices. This is happening because a web application is
easier to distribute. The biggest benefit is that there is no need to
create a separate application for each platform. The rule "write once,
run everywhere" can be applied.
Testing the functionality of these applications is therefore highly
focused on User Interface (UI) testing. One way of reducing the cost
of developing and testing applications is automated testing. Present
development of scripts for automated UI testing, however, suffers from
many drawbacks. The way, in which tests are written, is too on low
level and therefore verbose, and also tightly coupled with a specific
implementation details of applications. Therefore, often a small change
in the application leads to many changes in tests, and thus provides
more opportunities to introduce errors into the test. Development and
maintenance of such tests is therefore expensive [2].
This thesis is aimed at exploring and describing modern trends in
testing enterprise web applications in the first phase, then after the
investigation, it is aimed at selecting tools for automated testing of
these applications, comparing them according to maintainability, imple-
mentation of these tests and their usage in the systems of continuous
integration. This analysis should provide high level application pro-
gramming interface (API) for use in testing the component based web
application user interfaces.
The work’s goal is to improve readability of tests and therefore also
the maintainability by employing the created API in testing of enterprise
applications.
An API is successfully adapted by users when it provides a clear
contract for each component; it should be easily employed; it shall evoke
confidence in users that the authors are able to maintain the API, and
1
1. Introduction
2
2 Testing of enterprise web applications
Manual testing
It involves manual tasks, such as: setting up the test environment,
executing the tested functionality, collecting and reviewing the results
and recording found issues.
This process can be done by following a test plan or, alternatively,
by exploratory testing [5].
1. The process of creating a software product from its initial conception to its
release [4].
2. The person who either performs tests, or who develops them.
3
2. Testing of enterprise web applications
2008 [6] it should contain among other things: a test plan identifier, an
introduction, test items, the features to be tested, the features not to
be tested, an approach, item pass/fail criteria, and other prerequisites.
Because it uses a predefined plan to test an application, it does not
depend tightly on tester’s skills. On the other hand, it can be more time
consuming to create and maintain test plans.
Exploratory testing It is not tied with any test plan, hence requires
less time for preparation, and can discover important problems quickly.
The problems are that it is harder to reproduce any discovered
problems in later application development phases, and exploratory
testing also tightly depends on tester skills.
Automated testing
Execution of tests without human intervention can be defined as au-
tomated testing. Automated tests execution includes, however, other
prerequisites [7]:
4
2. Testing of enterprise web applications
3. Also called test driver, a tool used to execute and control tests.
5
2. Testing of enterprise web applications
White-box testing
It is also known as clear box testing, and denotes technique, when tester
knows the underlying implementation of an application, so he can decide
how to develop the tests according to this knowledge. It is used mainly
for checking small parts of an application, for example their database
transactions.
Black-box testing
It indicates the way of testing, where the tester does not know the details
of how the AUT works. An output of the tested action is important,
but not how the action was done. It is used mainly for testing of bigger,
already implemented parts of the AUT functionality.
Gray-box testing
6
2. Testing of enterprise web applications
Unit testing
A unit is the smallest testable piece of software which can be compiled
and put under test harness [10].
Unit testing (sometimes module testing [4]) is typically performed
as white-box testing (see section 2.1), because the tester needs to know
the code which he is going to test [11].
Scope of unit testing is narrow, in other words, it should verify small
parts of the entire application. An example of unit testing can be testing
of an unit which is responsible for computing factorial of a natural
number.
Unit tests are usually written by developers of the application, or
framework. The tests should be developed and executed in prior to or
during the implementation of the modules [11]. It is not necessary to
wait with testing of units until all units are implemented because they
should not have dependencies on each other.
4. There are more attributes for dividing testing methods into groups, see [8] for
basic overview.
5. For example linear development methodology called Waterfall recognizes these
development phases: Initial Investigation, Requirements Definition, System Design,
Coding and Testing, Implementation, Operation and Support [9].
7
2. Testing of enterprise web applications
Mock versus real objects testing "Not all code is self contained"
[16], in other words, real applications have a lot of dependencies. Unit
tests are intended to test as much independent modules as possible.
This is, however, very hard to achieve in real world applications.10
The tester then has basically three options:
• test with real objects;
8
2. Testing of enterprise web applications
Real objects Testing with real objects would mean to use some
of the dependencies the tested unit has. But this means relying on the
fact that used dependencies are correct, that they are tested somewhere
else [16]. Suppose the listing 2.1.
1 import j a v a . u t i l . L i s t ;
2 import j a v a . u t i l . A r r a y L i s t ;
3
4 import o r g . my . f o o . Equipment ;
5
6 public c l a s s Garage {
7
8 // w i l l r e t u r n f a l s e i f t h e r e was c o r r u p t e d t o o l .
9 public boolean c h e c k T o o l s C o n d i t i o n ( L i s t <Equipment> t o o l s
) {
10
11 int numberOfTools = t o o l s . s i z e ( ) ;
12
13 f o r ( int i = 0 ; i < numberOfTools ; i ++) {
14 boolean good = ( t o o l s . g e t ( i ) ) . c h e c k C o n d i t i o n ( ) ;
15
16 i f ( ! good ) {
17 return f a l s e ;
18 }
19 }
20
21 return true ;
22 }
23 }
9
2. Testing of enterprise web applications
1 import j a v a . u t i l . L i s t ;
2 import j a v a . u t i l . A r r a y L i s t ;
3
4 import o r g . my . f o o . Equipment ;
5
6 public c l a s s TestGarage {
7
8 @Test
9 public void t e s t C h e c k T o o l s C o n d i t i o n ( ) {
10 Equipment axe = new Equipment ( " axe " ) ;
11 axe . s e t C o n d i t i o n ( ConditionEnum .BAD) ;
12
13 L i s t <Equipment> t o o l s = new A r r a y L i s t <Equipment >() ;
14 t o o l s . add ( axe ) ;
15
16 Garage g a r a g e = new Garage ( ) ;
17 boolean r e s u l t = g a r a g e . c h e c k T o o l s C o n d i t i o n ( t o o l s ) ;
18
19 a s s e r t F a l s e ( r e s u l t , " The method d i d not d i s c o v e r
corrupted tool ! " ) ;
20 }
21 }
Mock objects One of the solutions for this is to use mock objects
instead of real objects.
Mock objects encourage testers to write better structured tests with
reduced dependencies. It is a technique used in TDD (Test-Driven-
Development12 ) [18].
In other words, tester will mock the services provided by other than
tested class. He will define the exact behaviour the services should have,
12. Software development methodology which among the other things, encourage to
write tests at first, then implementation [17].
10
2. Testing of enterprise web applications
and by this, he does not suppose that the services works as expected
any more. It does not have to be used only in TDD, but in other testing
methodologies as well.
In Java environment, there are several mocking frameworks. Listing
2.3 demonstrates creation of a mock object in Mockito13 for dependencies
from Listing 2.2.
1 import j a v a . u t i l . L i s t ;
2 import j a v a . u t i l . A r r a y L i s t ;
3
4 import o r g . my . f o o . Equipment ;
5
6 public c l a s s TestGarage {
7
8 @Test
9 public void t e s t C h e c k T o o l s C o n d i t i o n ( ) {
10 Equipment axe = new Equipment ( " axe " ) ;
11 axe . s e t C o n d i t i o n ( ConditionEnum .BAD) ;
12
13 L i s t <Equipment> t o o l s = Mockito . mock ( L i s t . c l a s s ) ;
14 when ( t o o l s . g e t ( a n y I n t ( ) ) ) . thenReturn ( axe ) ;
15 when ( t o o l s . s i z e ( ) ) . thenReturn ( 1 ) ;
16
17 Garage g a r a g e = new Garage ( ) ;
18 boolean r e s u l t = g a r a g e . c h e c k T o o l s C o n d i t i o n ( t o o l s ) ;
19
20 a s s e r t F a l s e ( r e s u l t , " The method d i d not d i s c o v e r
corrupted tool ! " ) ;
21 }
22 }
11
2. Testing of enterprise web applications
Integration testing
Next level after testing units, is testing of integrated units, so-called
integration testing (sometimes product testing [11]).
These units are considered to be flawless, as their unit tests are
passing without problems, and we want to verify that aggregating of
these components cannot create a problem. An example of such problems
can be incorrect return value of a method call, or insufficient validation
criteria [10].
A special kind of integration testing is application programming
interface17 (API) testing. It is used, for example, to validate REST18
API, or an API of web components, which is done for this thesis.
Integration testing can be performed as both white-box and black-box
testing (see section 2.2.2). It should be performed by an independent
test team, and can begin as soon as enough of the tested units are
implemented, or when units need to integrate with components outside
of system, for instance with database.
During this phase, all customer environment variations should be
considered and tested [11]. Meaning that, for example, all supported
Operating Systems or browsers should be combined and tested.
Automation of integration testing is even more difficult than unit
testing automation. It is because of integration-level complexity, which
is firstly caused by complicated initial system set-up. To test integration
15. More information about differences between stubs and mock objects can be
found at http://martinfowler.com/articles/mocksArentStubs.html.
16. An example of a stub created for this thesis is AbstractComponentStub, which
can be found in the api module.
17. API, a specification intended to be used as an interface for communicating
among software components [19].
18. REST,http://www.ics.uci.edu/~taylor/documents/2002-REST-TOIT.pdf.
12
2. Testing of enterprise web applications
13
2. Testing of enterprise web applications
System testing
Several units aggregated into one make a component; several components
integrated into one make one big component, called system.
Testing of such big component is called system testing [10]. It is
aimed to reveal problems which can be exposed by only testing the
entire integrated system or a major part of it. An example can be an
error exposed by different communication network protocol, used for
communicating with other components or systems [11], or in case of
web applications, testing of user interfaces.
It is an example of black-box testing (section 2.2.2) and it is the
third phase according to target testing, during which the test team
should replicate application user environment. It should begin after all
components functionality was implemented.
14
2. Testing of enterprise web applications
1 public c l a s s T e s t N a v i g a t i o n O v e r P a g e s {
2
3 private WebDriver d r i v e r ;
4
5 @Test
6 public void testPopup {
7 d r i v e r = new F i r e f o x D r i v e r ( ) ;
8
9 driver . get
10 ( " h t t p : / / l o c a l h o s t : 8 0 8 0 / myTestApp/ i n d e x . html " ) ;
11
12 d r i v e r . f i n d E l e m e n t (By . i d ( " button " ) ) . c l i c k ( ) ;
13
14 WebElement popup = d r i v e r . f i n d E l e m e n t
15 (By . xpath ( " //∗ span [ @id=’popup ’ ] " ) ) ;
16
15
2. Testing of enterprise web applications
• Tests maintenance;
• Inability to test every aspect of the application
• Reliability of tests
• Non-effectiveness for some agile development methods
• Re-usability of the tests
• Slow speed of test execution
20. The deficiencies are not caused by tool selecting, they are very common for all
such tools.
21. It is a way of forcing a developer to use some particular type of the object, to
ensure discovery of type errors at compile time.
22. There are currently some tools which leverage some of the visual testing burdens,
but they can not still fully replace a human.
16
2. Testing of enterprise web applications
17
2. Testing of enterprise web applications
2.3.2 Problems
The benefits which CI brings outweigh the disadvantages, but they need
to be considered as well. The most critical are:
18
2. Testing of enterprise web applications
• Performance;
• Data persistence;
• Numerous UI screens;
• Security.
19
2. Testing of enterprise web applications
20
2. Testing of enterprise web applications
21
2. Testing of enterprise web applications
22
3 Evaluation of the tools
23
3. Evaluation of the tools
• Geb [33]
3. DI, http://martinfowler.com/articles/injection.html.
4. Selenium 2, http://seleniumhq.org/.
5. Selenium, http://seleniumhq.org/docs/03_webdriver.html.
24
3. Evaluation of the tools
6 @Drone
7 protected AjaxSelenium s e l e n i u m ;
8
9 @Test
10 public void t e s t A j a x I n p u t ( ) {
11
25
3. Evaluation of the tools
22
23 S t r i n g actualOutput =
s e l e n i u m . getText ( ajaxOutput ) . t r i m ( ) ;
24 a s s e r t E q u a l s ( actualOutput , t e s t S t r i n g , " The output
g e n e r a t e d by Ajax i s not c o r r e c t ! " ) ;
25 }
26 }
3.2.2 Geb
Geb is the second chosen tool. It also uses WebDriver internally together
with JQuery8 content selection. It is similar to Arquillian Drone in terms
of cross-browser testing and ability to test asynchronous pages.
The differences from Arquillian Drone is that the test scenarios
are written in Groovy. And it also lacks the Arquillian support for
management of test life cycle. Apache Maven can be used for building.
Support for Gradle9 and Grails.10 is added.
An example of test written in Geb is shown in Listing 3.2. The test
scenario is the same as in listing 3.1.
On line 2, it is accessing the URL on which the tested application is
deployed, line 4 ensures that the tested page was completely loaded.
On line 6, it is using JQuery like syntax for locating of element with
class myInput, and consequently the found element is filled with value
Test String.
Line 8 asserts that the element with class myOutput was updated
with expected value.
8. JQuery, http://jquery.com/.
9. Gradle, http://www.gradle.org/.
10. Grails, http://grails.org/.
26
3. Evaluation of the tools
1 Browser . d r i v e {
2 go " h t t p : / / l o c a l h o s t : 8 0 8 0 /myApp/ i n t e x . html "
3
4 a s s e r t t i t l e == "MyApp"
5
6 $ ( " i n p u t " , c l a s s : " myInput " ) . v a l u e ( " Test S t r i n g " )
7
8 waitFor { $ ( " d i v " , c l a s s : " myOutput " ) . t e x t ( ) == " Test
String " }
9 }
27
4 Component Model
A component is a basic unit of the component-based Web frameworks
(section 4.1.1). That is, for instance a calendar component. A graphical
representation of the calendar component can be found in the figure 4.1.
The term component model is used for the purpose of this thesis as
a term for referencing an abstract API an its implementation, that was
created for this thesis.
28
4. Component Model
date to the calendar will be correctly reflected in the input for that
calendar.
Note the differences: whereas in the first example the structure of
the web page is hard-coded in the test, the second example uses services
of calendar component which encapsulates that structure to achieve the
same functionality. This way it is more visible what the purpose of test
is. Furthermore, the more readable the code is, the better maintainable
it is.
1 public c l a s s T e s t C a l e n d a r {
2
3 @FindBy ( xpath = " // d i v [ @id=’ ro ot E le me nt ’ ] " )
4 R i c h F a c e s C a l e n d a r c a l e n d a r = new
RichFacesCalendar ( " locatorDeterminingCalendar " ) ;
5
6 @Test
7 public void t e s t A j a x I n p u t ( ) {
8 Date e x pe c t ed D a te = new Date ( ) ;
9
10 c a l e n d a r . show ( ) ;
11 c a l e n d a r . setToday ( ) ;
12
13 Date a c t u a l S e t D a t e = c a l e n d a r . g e t S e t D a t e ( ) ;
14
15 checkThatDatesAreSame ( expectedDate , a c t u a l S e t D a t e ) ;
16 }
17 }
1 public c l a s s T e s t C a l e n d a r {
2
3 protected JQueryLocator imgWhichInvokesTheCalendar =
j q ( " img . r f −c a l −btn " ) ;
4 protected JQueryLocator applyButton =
j q ( " d i v [ o n c l i c k ∗= c l o s e ] : c o n t a i n s ( ’ Apply ’ ) " ) ;
5 protected JQueryLocator todayButton =
j q ( " d i v [ o n c l i c k ∗=today ] : v i s i b l e " ) ;
6 protected JQueryLocator c a l e n d a r I n p u t =
j q ( " . r f −c a l −i n p " ) ;
7
8 @Test
29
4. Component Model
9 public void t e s t A j a x I n p u t ( ) {
10 s e l e n i u m . c l i c k ( imgWhichInvokesTheCalendar ) ;
11
12 waitGui . f a i l W i t h (new RuntimeException ( " Calendar was
not opened ! " ) )
13 . timeout (1000)
14 . u n t i l ( e l e m e n t V i s i b l e . l o c a t o r ( todayButton ) ) ;
15
16 s e l e n i u m . c l i c k ( todayButton ) ;
17 s e l e n i u m . c l i c k ( applyButton ) ;
18
19 waitGui . f a i l W i t h (new RuntimeException ( " Calendar was
not c l o s e d ! " ) )
20 . timeout (1000)
21 . u n t i l ( e l e m e n t N o t V i s i b l e . l o c a t o r ( todayButton ) ) ;
22
23 Date e x pe c t ed D a te = new Date ( ) ;
24 Date a c t u a l S e t D a t e =
parseDateFromInput ( c a l e n d a r I n p u t ) ;
25
26 checkThatDatesAreSame ( expectedDate , a c t u a l S e t D a t e ) ;
27 }
28 }
Moreover this API does not have to reflect only on specific implemen-
tation of UI components, it can be transformed to provide unified API
for various UI component libraries. These libraries can be collectively
called component based frameworks.
30
4. Component Model
with the view layer by providing set of core components which pull
results from multiple controllers3 as needed. [36] This means that, the
components are managing the requests on their own, they do not need
the developer to implement various interfaces to achieve the desired
functionality. Examples of such frameworks are: JSF (Java Server Faces),
Tapestry, Wicket, GWT (Google Web Toolkit), Vaadin as well as Stripes.
Component oriented4 frameworks can be identified also in other
environments apart from Java. For instance ASP.NET Web Forms
is a framework which also provides set of components for which the
component model can be created.
The last example of the environment where Web components play a
significant role is JavaScript environment, an example is the jQuery UI
framework.
All above mentioned frameworks have one important characteristic
in common: each component has predefined the HTML mark-up code
which is rendered on the client side (browser) and also the JavaScript
sources which are either included or imported to the page sources
rendered by the browser.
This particular specific of these frameworks enables us to create an
implementation of the predefined abstract component model in a way
that allows all users of that framework to employ it.
3. Controller is that part of the MVC which handles user input and controls the
data flow from business logic to the View layer.
4. Do not meet all the specifics of the component based frameworks.
31
4. Component Model
32
4. Component Model
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 inputArea ;
8
33
4. Component Model
34
4. Component Model
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 webDriver ;
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 ( " sk " ) ) ;
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 wordToTranslate = " ryba " ;
15 String expectedTranslation = " f i s h " ;
16
17 String actualTranslation =
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.
35
4. Component Model
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.
8. Java Exception thrown e.g. when invoking method on field with null value.
36
4. Component Model
37
4. Component Model
Figure 4.3: Google Translate Web page screenshot (20th April 2012)
with components identified.
9. Javadoc - way of creating documentation for Java methods, classes and other
structures.
38
4. Component Model
Java Reflection
Reflection is a feature of Java language, used by programs to examine, or
modify the runtime behaviour of applications. It is an advanced feature
which needs to be employed with following concerns kept in developer’s
mind [40]:
39
4. Component Model
Listing 4.4 shows an example of Java class and its fields declared on
lines 4 and 7, its method on line 10. That class does not have defined
constructor explicitly, therefore a default one is defined for it.
Wile using reflection it is possible to for example access and manip-
ulate this class, its fields and constructors during runtime. Listing 4.5
shows an example of such manipulation with this class. On line 5, all
declared fields are retrieved. On line 7 we are iterating over this array of
all declared fields, retrieving the name of the field, its annotation Page
if exists, information whether the field is accessible, and its generic type.
On line 20, there is a demonstration of a way of creating new instances
of classes.
1 public c l a s s S h o w c a s e R e f l e c t i o n C a p a b i l i t i e s {
2
3 public s t a t i c void main ( S t r i n g [ ] a r g s ) throws
InstantiationException , IllegalAccessException {
4
5 Field [ ] declaredFields =
TestGoogleTranslate . class . getDeclaredFields () ;
6
7 for ( F i e l d i : d e c l a r e d F i e l d s ) {
8 S t r i n g name = i . getName ( ) ;
9 Page a n n o t a t i o n = i . g e t A n n o t a t i o n ( Page . c l a s s ) ;
10 boolean i s A c c e s s i b l e = i . i s A c c e s s i b l e ( ) ;
11 Type type = i . getType ( ) ;
12
13 System . out . p r i n t l n ( name ) ;
14 System . out . println ( annotation ) ;
15 System . out . println ( isAccessible ) ;
16 System . out . p r i n t l n ( type ) ;
17 System . out . println () ;
18 }
19
20 TestGoogleTranslate instance =
TestGoogleTranslate . class . newInstance ( ) ;
21 System . out . p r i n t l n ( i n s t a n c e ) ;
22 }
23 }
40
4. Component Model
There are several reasons for creating a surrogate object, and then
the names of the proxies are inferred from this reasons; for example it
is created to control access to a network resources (Firewall Proxy), it
can be created to provide temporary storage for results of expensive
operations (Caching Proxy), or to act as local representative for an
object that does run in the same address space (Remote Proxy), in the
case of Java language, in the same JVM.
Java Dynamic Proxies is a mechanism for creating a Proxy object
at runtime, that implements an interface, or multiple interfaces, and
forwards methods invocations to a specified class. They are created as
stated in the previous section with use of Java Reflection API. The
41
4. Component Model
class diagram for Java Dynamic Proxy (Figure 4.5) differs a little
from the general Proxy class diagram, because it is supplemented with
InvocationHandler class. Its purpose is to respond to any method calls
on the Proxy; it is the way of declaring what Proxy has to do before
invoking method on the real object [39].
An example of the Java Dynamic Proxies use case is creating dynamic
mock objects for unit testing.
Figure 4.5: UML Class diagram for Java Dynamic Proxy Pattern.
Java Generics
Java Generics is a feature added to Java language in version 1.3. Its
main purpose is to enhance type-safety. Consider following Listing 4.6,
which demonstrates the problems, when not using Java Generics.
The class Drawer enables to add any object to it, because its field
is of the Object type, which is the super type of all Java objects.
The main method of the class ShowcaseGenericProblems is compiled
without problems, however, when running, ClassCastException Java
exception is thrown because of line 20, where we are trying to cast
an object of type String to an object of type Object. This is just an
artificial example, but similar problem can easily occur in real-world
examples. The main problem is that it is not caught at compile time,
but it is exposed during runtime.
Listing 4.7 solves this problem by using of Generics.
GenericDrawer has generic type T, which can be supplemented by
42
4. Component Model
any type, and the return value of method getItem is also of the generic
type T. In the main method of the class GenericsSolution, we are per-
forming the same scenario as in previous example, only the instantiation
of the class Drawer uses generics now. Note that is not possible to even
compile GenericsSolution class, we get the error message "Cannot
cast from String to Integer". The result is expected and desired as we
want to catch this type of errors during compile time.
1 public c l a s s GenericDrawer<T> {
2
3 private T item ;
4
5 public void addItem (T item ) {
6 t h i s . item = item ;
7 }
8
9 public T g e t I t e m ( ) {
10 return t h i s . item ;
11 }
12 }
13
14 public c l a s s G e n e r i c s S o l u t i o n {
15
21 I n t e g e r pen = ( I n t e g e r ) drawer . g e t I t e m ( ) ;
22 }
23 }
1 public c l a s s Drawer {
2 private Object item ;
3
4 public void addItem ( Object item ) {
5 t h i s . item = item ;
6 }
7
8 public Object g e t I t e m ( ) {
43
4. Component Model
9 return t h i s . item ;
10 }
11 }
12
13 public c l a s s ShowcaseGenericProblems {
14
15 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
16
17 Drawer drawer = new Drawer ( ) ;
18 drawer . addItem ( " pen " ) ;
19
20 I n t e g e r pen = ( I n t e g e r ) drawer . g e t I t e m ( ) ;
21 }
22 }
2. You have to identify the provided service by placing a file into the
directory where the sources of your application are, and under
it to the directory /META-INF/services, which contains a fully
qualified service name16 .
44
4. Component Model
WebDriver
WebDriver automation tool is already mentioned in the section 3.2. In
the created abstract model, it will be the main automation tool, in other
words, it will be used to make interactions with the browser.
Currently, Arquillian Graphene is used to obtain an instance of
WebDriver, which is subsequently injected into the test object.
To instruct WebDriver what web page element we want to com-
municate with, it uses already seen mechanism of WebElement. For
example line 4 at Listing 4.3 declares such a WebElement by specifying
the XPath of the particular element which is in that example string
//input[@type=’submit’].
XPath is a way of navigation in an XML document, and the structure
of all web pages is also connected with their Document Object Model
(DOM) which is a tree model of all web page elements, constructed in
an XML syntax. This particular string locates a submit button. There
are also other ways of locating web elements, such as CSS selectors.
45
4. Component Model
46
4. Component Model
Arquillian Drone
After the creating a prototype for the first selected component, calendar
(its implementation in Listing 4.9), the usage of this component in the
test looked like Listing 4.10.
The Calendar component from listing has two fields, one annotated
with Root annotation, which represented the field for later setting of
the actual root, and the second annotated with annotation FindBy with
47
4. Component Model
48
4. Component Model
1 public c l a s s CalendarImpl {
2
3 @Root
4 private WebElement r o o t ;
5
6 @FindBy ( c s s = " img : nth−of −type ( 1 ) " )
7 private WebElement showCalendarButton ;
8
9 public void showCalendar ( ) {
10 showCalendarButton . c l i c k ( ) ;
11 }
12 }
1 public c l a s s TestPageWithCalendar {
2
3 private CalendarImpl c a l e n d a r ;
4
5 @BeforeClass
6 public void i n i t C a l e n d a r ( ) {
7 calendar =
Fa ctor y . i n i t i a l i z e C o m p o n e n t ( CalendarImpl . c l a s s ) ;
8 }
9
10 @BeforeMethod
11 public void lo adT estPag e ( ) {
12
13 webDriver
14 . g e t ( " h t t p : / / l o c a l h o s t : 8 0 8 0 / myTestApp/ c a l e n d a r . j s f " ) ;
15
16 c a l e n d a r R o o t = webDriver
17 . f i n d E l e m e n t (By . xpath ( " // td [ @ c l a s s =’ e c o l 1 ’ ] " ) ) ;
18 calendar . setRoot ( calendarRoot ) ;
19 }
49
4. Component Model
20
21 @Test
22 public void t e s t C a l e n d a r S e r v i c e ( ) {
23 c a l e n d a r . showCalendar ( ) ;
24 }
25
26 }
50
4. Component Model
Good API design First of all, when creating an object oriented (OO)
API, all the OO principles, like encapsulating what varies, favouring
composition over inheritance, program to interfaces not implementations,
do not call us we call you [39], need to be followed to be successful.
However, it is not sufficient for creating an API, it can be sufficient for
creating an application with use of that API.
Jaroslav Tulach, a founder and initial architect of NetBeans IDE,
and currently the development lead advises to keep in mind following
principles when creating an API [43]:
You have to develop a trusting relationship between you and other
programmers, you have to convince them that you are able to produce
and maintain stable API. In practice it can means to maintain backward
compatible API, which is an API which when evolves, the older contract
of the API remains the same, while new functionality is added. To be
more specific, when implementing an interface in Java, it can not happen
that new methods with new releases will be added to that interface, as
it would break the whole code, because the implementations would not
contain the new methods.
It is important to be use case oriented. It is not possible to know all
API users, and therefore their needs. Therefore the solution is to be use
case oriented, what means to work with vision of users’ actions. The
starting point of any design should be answering the questions: Why ?
What ? How ?
That is why we started with possible use cases of future components.
Their can be clearly viewed from Unified Modeling Language 2 diagrams
51
4. Component Model
52
4. Component Model
2. Then he can fill in the input with prefix of word, which should
not have any suggestions, and assert the expected state.
53
4. Component Model
• get all values from the input, which were filled in with autocom-
pletition from a suggestion list;
54
4. Component Model
Figure 4.10 shows possible use cases of the Table component. The
component should provide a way to get any part of the table, like
particular cell, column or row and also their content (e.g. Get Any
Part of Table, Get Table Header/Footer, Get Content of Table Part).
It should also be possible also to find parts of the table according to
some filter function (Find Parts of Table, Determine Which Parts of
Table). The last example of functionality is a mechanism for iterating
over multiple table pages.
Appendix E.1 shows possible test scenario of table component. With
regards to Figure 4.9, typing values into the input nested in the header
causes triggering of filter function, which subsequently renders only rows
which conform the filtering function.
The test scenario is based on this functionality, therefore the first
step is to create a table with particular columns, get the input element
from the first header cell, type a string into that input, and iterating
over rendered filtered rows, to assert that they contain only values which
agree with the filled in value.
55
4. Component Model
56
4. Component Model
2. set the date, for example a month and two days after current
date to the second calendar, that would represent an end of the
activity.
57
4. Component Model
3. Get the selected dates from both calendars, and verifies that
expected dates were selected.
58
4. Component Model
21. API for Calendar uses Joda Time library, which enhances the standart
java.util.Date and java.util.Calendar libraries, and improves flaws in their desing.
Available at http://joda-time.sourceforge.net/.
59
4. Component Model
1. Fill all inputs with correct data, that means, data which pass
length and other validation criteria. There are five ordinary
inputs, one with auto-complete function and two calendars, which
need to be completed in order to proceed in the service ordering.
2. Select the service from the third row of the table by selecting
the check-box and filling in the number spinner input value 4.
60
4. Component Model
Arquillian Drone tests, which uses WebDriver as test harness (see the
section 2.2.1).
For the purpose of demonstrating only differences of writing tests
with use of component model API and without it ,some important
parts needed for executing these tests are omitted, for example, the
need of initialising the FindBy annotations for listing which does not
use component model, or methods which take care of deployment of
application to test.
61
4. Component Model
62
5 Conclusion
The aim of this thesis was to explore and to describe modern trends
in testing enterprise web applications. After the research, tools for
automated testing of these applications were selected and compared.
The main focus was on maintainability and implementation of tests
developed by the tools and their usage in the systems of continuous
integration. Based on this analysis, I was supposed to provide high level
application programming interface that could be used in testing the
component based web application user interfaces.
The major contribution of this thesis is the created high level API,
as it improves maintainability of tests by increasing their readability, by
more accurately reflecting the intention of a test script. I also proved
that employing a created API can save valuable code lines of tests in
some cases up to 39%. Use of created API also increases the robustness
of tests, by encapsulating the structure of web pages in the created
model. This reduces the scope for introducing an error in the test since
any change in the structure of web pages will appear in one place.
I have designed API for nine web components, including highly
complex one, table. Programmed implementation of the API for web
framework RichFaces is currently used mainly for thesis presentation
purposes. Based on the analysis of automation tools for testing the UI, I
chose Arquillian Drone instrument, and I I managed to integrate it with
API. By implementing this integration I was able to learn lot of Java
specific frameworks and APIs, for example Reflection API, SPI and Java
Dynamic Proxies. I was also able to grasp and employ object oriented
design patterns, for example Proxy pattern, Page Objects pattern and
Command pattern. This integration improves the usability of the API,
and by the fact that it is based on known and by a wide community of
developers respected instruments, it is also ready for being adopted by
that community. The created solution is suitable for use in the enterprise
sector, and its benefits can help reduce costs needed for development,
testing and maintaining software.
There are several possible extensions of this thesis, among others it
includes designing APIs for other web components and complete the
outlined implementation for RichFaces web framework. The intention is
to open source this project, to enable the community around UI testing
63
5. Conclusion
64
Bibliography
[1] James Bach. Test Automation Snake Oil. http://www.satisfice.
com/articles/test_automation_snake_oil.pdf, 1999. [Online;
accessed 13-May-2012].
[5] Cem Kaner, Jack Falk, and Hung Nguyen Q. Testing Computer
Software, volume 2. Van Nostrand Reinhold, 1993.
65
5. Conclusion
[11] Cynthia Lovin and Tony Yaptangco. Best Practices: Enterprise Test-
ing Fundamentals. http://www.dell.com/downloads/global/
power/ps1q06-20050111-Lovin.pdf, 2006. [Online; accessed 13-
May-2012].
[18] Steve Freeman, Nat Pryce, Tim Mackinnon, and Joe Walnes. Mock
Roles, not Objects. http://www.jmock.org/oopsla2004.pdf,
2004. [Online; accessed 13-May-2012].
66
5. Conclusion
67
5. Conclusion
[39] Eric Freeman, Elisabeth Freeman, Kathy Sierra, and Bert Bates.
Head First Design Patterns. O’Reilly Media, Inc., 2004.
68
A Example of UI test verbosity
1 public c l a s s Meetup {
2
3 // d e c l a r a t i o n o f used f i e l d s
4
5 @Test
6 public void l i s t R e s p o n s e s ( ) {
7
8 // open t h e e v e n t page
9 d r i v e r . g e t ( " h t t p : / /www. meetup . com/ " + meetup +
" / calendar / " + event + " / " ) ;
10
11 i f ( d r i v e r . f i n d E l e m e n t (By .
12 xpath ( " i d ( ’ C_document ’ ) / d e s c e n d a n t : : " +
13 " d l [ @ c l a s s =’ s t a t s ’ ] [ 2 ] / dt " ) ) .
14 getText ( ) . e q u a l s ( "Who ’ s coming ? " ) ) {
15 // t h i s e v e n t has not y e t o c c u r r e d
16 listMembers
17 ( " i d ( ’ C_document ’ ) // l i [ d i v [ @ c l a s s=" +
18 " ’ D_attendeeHeader D_yes ’ ] ] " +
19 " // l i [ s t a r t s −with ( @id , ’ member_ ’ ) ] " , " Yes " ) ;
20 listMembers
21 ( " i d ( ’ C_document ’ ) // l i [ d i v " +
22 " [ @ c l a s s =’ D_attendeeHeader D_maybe ’ ] ] " +
23 " // l i [ s t a r t s −with ( @id , ’ member_ ’ ) ] " ,
" Maybe " ) ;
24 listMembers
25 ( " i d ( ’ C_document ’ ) // l i [ d i v " +
26 " [ @ c l a s s =’ D_attendeeHeader D_no ’ ] ] " +
27 " // l i [ s t a r t s −with ( @id , ’ member_ ’ ) ] " , "No" ) ;
28 } else {
29 // t h i s e v e n t i s i n t h e p a s t
30 l i s t M e m b e r s ( " i d ( ’ C_document ’ ) // " +
31 " l i [ s t a r t s −with ( @id , ’ member_ ’ ) ] " ,
" Attended " ) ;
32 }
33 }
34
35 // o t h e r methods i m p l e m e n t a t i o n
69
B Factory class and its methods
1 public c l a s s Fa ctor y {
2
3 public s t a t i c <T extends AbstractComponent> T
i n i t i a l i z e C o m p o n e n t ( C l a s s <T> c l a z z ) {
4 AbstractComponent component =
instantiateComponent ( c l a z z ) ;
5
6 Field [ ] declaredFields = clazz . getDeclaredFields () ;
7
70
B. Factory class and its methods
37 .
38 .
39 i f ( j instanceof FindBy ) {
40
41 WebElement r e f e r e n c e d E l e m e n t =
42 ( WebElement )
43 Proxy . newProxyInstance
44 ( WebElement . c l a s s . g e t C l a s s L o a d e r ( ) ,
45 new C l a s s <? >[] { WebElement . c l a s s } , new
InvocationHandler () {
46
47 @Override
48 public Object i n v o k e ( Object proxy , Method method ,
Object [ ] a r g s ) throws Throwable {
49 WebElement r o o t = r o o t R e f e r e n c e . g e t ( ) ;
50
51 i f ( r o o t == null ) {
52 throw new RuntimeException ( " You have t o s e t
root element c o r r e c t l y ! " ) ;
53 }
54
55 WebElement myElement = r o o t . f i n d E l e m e n t ( findBy ) ;
56 return method . i n v o k e ( myElement , a r g s ) ;
57 }
58 }) ;
59
60 i . s e t ( component , r e f e r e n c e d E l e m e n t ) ;
61 }
62 }
63 }
64
Listing B.1: Factory class with its methods used to initialise given
component.
71
C Test enricher
1 public c l a s s E n r i c h e r implements T e s t E n r i c h e r {
2
3 @Override
4 public void e n r i c h ( Object t e s t C a s e ) {
5
6 // a t f i r s t i n i t i a l i z e findBy a n n o t a t i o n s
7 i f ( R e f l e c t i o n H e l p e r . i s C l a s s P r e s e n t (FIND_BY_ANNOTATION) )
8 {
9
10 initFieldsAnnotatedByFindBy ( testCase ) ;
11 }
12 // i n i t i a l i z e Page o b j e c t s i f t h e r e a r e any
13 i f ( R e f l e c t i o n H e l p e r . i s C l a s s P r e s e n t (PAGE_ANNOTATION) )
14 {
15
16 L i s t <F i e l d > f i e l d s =
ReflectionHelper . getFieldsWithAnnotation (
17 t e s t C a s e . g e t C l a s s ( ) , Page . c l a s s ) ;
18
19 i n i t i a l i z e P a g e O b j e c t F i e l d s ( testCase , f i e l d s ) ;
20 }
21 }
72
D Sequence Diagram of Autocomplete Com-
ponent
73
E Sequence diagram of Table Component
74
F Sequence Diagram of Calendar Popup
Component
75
G Omitted Arquillian test configuration.
4 @Deployment ( t e s t a b l e = f a l s e )
5 public s t a t i c WebArchive d e p l o y ( ) {
6 MavenDependencyResolver r e s o l v e r =
D e p en d e n cy R e s o l ve r s .
7 u s e ( MavenDependencyResolver . c l a s s )
8 . loadMetadataFromPom ( "pom . xml " ) ;
9
10 WebArchive war = ShrinkWrap
11 . c r e a t e ( WebArchive . c l a s s , " f t e s t −app . war " )
12 . a d d A s D i r e c t o r i e s ( Archi vePaths .
13 create ( " templates " ) )
14 . addAsWebResource (new F i l e (WEBAPP_SRC +
" / t e m p l a t e s / t e m p l a t e . xhtml " ) ,
15 Archi vePaths .
16 c r e a t e ( " t e m p l a t e s / t e m p l a t e . xhtml " ) )
17 . addAsWebInfResource (new F i l e (WEBAPP_SRC +
" /WEB−INF/web . xml " ) )
18 . addAsWebInfResource (new F i l e (WEBAPP_SRC +
" /WEB−INF/ f a c e s −c o n f i g . xml " ) )
19 . addAsLibraries (
20 resolver . artifacts
21 ( " org . r i c h f a c e s . ui : " +
22 " r i c h f a c e s −components−u i " ,
23 " org . r i c h f a c e s . core : " +
24 " r i c h f a c e s −c o r e −impl " )
25 . resolveAsFiles () ) ;
26
27 return war ;
28 }
29 }
76
H Manual for building showcase applica-
tion
To build showcase application, you need to do following:
77
I Functional test without using of Compo-
nent Model
78
I. Functional test without using of Component Model
68 calendarFromInvokeButton . c l i c k ( ) ;
69 (new WebDriverWait ( webDriver , 2 ) )
70 . u n t i l (new ExpectedCondition <Boolean >() {
71
72 public Boolean apply ( WebDriver d ) {
73
74 return fromCalendarTodayCell . i s D i s p l a y e d ( ) ;
75 }
76 }) ;
77
78 DateTime today = new DateTime ( ) ;
79 int dayNumber = today . getDayOfMonth ( ) ;
80
79
I. Functional test without using of Component Model
81 webDriver . f i n d E l e m e n t (By . i d ( f r o m C a l n e d a r C e l l I D +
( dayNumber − 1 ) ) )
82 . click () ;
83
84 c a le n da r T oI n v ok e B ut t o n . c l i c k ( ) ;
85 (new WebDriverWait ( webDriver , 2 ) )
86 . u n t i l (new ExpectedCondition <Boolean >() {
87
88 public Boolean apply ( WebDriver d ) {
89
90 return t o C a l e n d a r T o d a y C e l l . i s D i s p l a y e d ( ) ;
91 }
92 }) ;
93
94 webDriver . f i n d E l e m e n t (By . i d ( f r o m C a l n e d a r C e l l I D +
( dayNumber + 3 ) ) )
95 . click () ;
96
97 numberSpinnerFromThirdRow . sendKeys ( " 4 " ) ;
98 i f ( ! checkboxFromThirdRow . i s S e l e c t e d ( ) ) {
99 checkboxFromThirdRow . c l i c k ( ) ;
100 }
101
102 submitButton . c l i c k ( ) ;
103
80
J Functional test with using of Component
Model
38 @Test
39 public void
40 test () {
81
J. Functional test with using of Component Model
41
68 a s s e r t F a l s e ( v a l i d a t i o n . isThereAnyErrorMessage ( ) ,
69 " There s h o u l d be no e r r o r me ssa ges ! " ) ;
70
71 a s s e r t T r u e ( proceedButton . i s D i s p l a y e d ( ) ,
72 " Proceed button s h o u l d be v i s i b l e i n t h i s moment ! " ) ;
73 }
82
K Contents of Attached CD
The attached CD contains following directories and files:
83