Test automation using Ruby and WATIR

Dear visitors of the resource habrahabr.ru! We want to introduce you to an article by Jeremy Suarez, Test Automation Engineer. If you plan to organize automated testing on your project using the Ruby and WATIR languages, this article will come in handy for you. Jeremy describes everything in simple language, using elementary examples. After reading the article you will have a clear understanding of the process - from its initial steps to the final stage.
Before we go directly to the material, I would like to devote a few words to the author. Jeremy has extensive experience in testing. On his many projects, he held various roles - from the developer, to the tester and project manager. He currently works for ThoughtWorks.
So let's get started!
Target audience
This material will be useful primarily to test engineers who plan to create automated test scripts, or for those who are going to support a ready-made framework. It is assumed that the reader has basic knowledge of Ruby syntax and is familiar with the basic principles of developing web applications (terms such as “link”, “form”, “JavaScript” do not lead to a panic attack).
Ruby is a relatively easy-to-learn language. If you already have some experience writing code in Python, C ++, Java, or C, you will quickly learn it.
Preconditions and Limitations
Here are some of the prerequisites for using WATIR for testing web applications. Perhaps the main one is that the module only works with IE 5.5 and below. Unfortunately, it is not designed to work with Netscape, Opera, Firefox, or any other browser. This means that cross-browser testing using WATIR is not possible. The second important detail is that WATIR does not have its own recorder. By and large, WATIR is a library of IE methods and objects that you can use when writing scripts manually. And finally, the third - WATIR has no means to identify objects located on the page, as well as their types and available methods. It provides methods for collecting all links, images, forms, etc. Therefore, the script development process often follows the trial and error method, which, incidentally, is not necessarily bad.
Preparation
Any process of writing automated test scripts must be preceded by a preparation process. The most important point in this case, perhaps, is that all auto-tests, in fact, logically follow from ready-made, manual test scripts. Most of the effort to develop a test framework is wasted due to incorrectly written manual tests. It is important to understand - this is the main point in the further support of both manual and automated testing. It is necessary to see the full picture of the interaction of business processes implemented using the application and to approach their description covering the entire scope of tasks.
Understanding the specifics of the application under test.
Collection of functional requirements (if any).
Before proceeding directly to the design of manual or auto tests, you need to understand what your application is all about. The easiest way is to familiarize yourself with the development requirements. Nowadays, documentation of requirements is ubiquitous. And if there are clearly articulated, complete and consistent requirements, this is a good starting point.
Survey of experts
In addition to studying functional requirements, or, if they are not, information can be obtained directly from the developers of the product, as well as end users. Usually architects, business analysts, etc. can also take part in this process. It is important that as many experts from different fields as possible participate in the discussion, since developers usually have their own idea of how the application should work. And as a rule, their point of view differs from the expectations of the client.
Presentation of a business process through test cases
All testing activities, whether manual or automated, should be based on detailed step-by-step test scripts. Without this, it becomes problematic to track the testing progress, as well as the percentage of code coverage and other metrics. It is wrong to think that auto-tests are their own documentation. They are constantly changing, being edited. Such an approach leads to time consuming and error multiplication.
Creating a data preparation process
Many applications use or create some data in their work. For testing purposes, both manual and automated, the state of the data in the system should be the same from cycle to cycle. Depending on what exactly the program should do in this case — to collect, create, or both, data preparation scripts should be prepared, as well as cleaning scripts. Tests for the preparation and purification of data should be formalized in the same way as ordinary scripts and used as preconditions in the latter.
Identify cases suitable for automation
As the famous advertising slogan says: "Not all yogurts are equally useful." The same applies to test cases. Not all of them should be automated. Only the simplest and most frequently repeated are good candidates. Start with cases that work with the UI, then pay attention to those during which you often need to create and delete data. In the end, try creating a set of scripts that cover the most important functional segments (the most commonly used functions).
Creating an automated scripting framework
As soon as you have a clear vision of what exactly needs to be tested, after you document the required functions as step-by-step cases, then you can safely start developing the auto-test scripts themselves. Copy your manual test case into an empty Ruby script file. Comment out the steps in the script and divide them into separate sections. When dividing, you can also follow the principle of creating data in one place, use in another. If during the work of the script some data was generated, but the case itself for some reason did not reach the end, it would be more reasonable to delete this data and try to restore the script.
Implementation
In general, the implementation of the test script automation process using Ruby and WATIR comes down to a few simple steps:
• A test case is selected and can be programmed using a set of functions
• Initialization of an IE object or connection to an existing browser window
• Navigation to the application’s initial link
• Collection of all links, images, forms necessary for further actions
• The name of the link is obtained from the collected information about the form, the name of the picture, etc.
• Performing actions on the link, form, image
• Repeat steps 3-6 until necessary. At the end of each step there should be a check that the action performed has ended successfully.
To achieve maximum efficiency, it is extremely important to accompany each step with verification. If such a check is not performed - you can - you can take a screenshot, copy the logs, or at least issue a sensible error message. Otherwise, you run the risk of getting something like “Link not found” or “Form xxx not available.”
Only on the developer of the script depends on how informative the error message will be if something went wrong. Low-quality scripts will have to be run manually to understand what all the same happened, and while a correctly compiled script is able to produce all the necessary information about the failure itself.
Technical Aspects of Implementation
Initializing an IE Object
Start by creating a new IE browser object or connect to an existing one.
$ ie = IE.new ()
Or
$ ie = IE.attach (: title, “...”) Follow the
start link
Start testing the application by clicking on the given link. All cases start with this. And sometimes it is necessary to follow the links during the execution of the script itself.
$ ie.goto (“http: // ....”)
Content
verification The easiest way to verify content is with the assert command. Check that the form exists, any button is available, the page contains some text, and so on ... There is no TRY loop in Ruby, for this reason we use the rescue keyword.
begin
assert ($ ie.pageContainsText (“Logged out Successfully”))
assert ($ ie.form (: name, “Login”). exists)
$ log.info (“Test step 5 passed!”)
rescue
$ log.error (“Test step 5 failed”)
$ log.info (“Error text was:“, ie.text ())
end
Gathering the necessary links, images, forms
When writing a script, it is not always easy to determine the exact name links or pictures, URL format, field names, etc. In such cases, you can upload the dump to a log file or to the screen. This information will be useful when creating a test or debugging it, but it should be disabled in the final version of the case. The output can also be output to files and to standard output devices.
$ log.info (), $ log.error (), $ log.warning () all output to the log4j log file.
Show all links:
puts $ ie.show_links ()
Show all forms:
puts $ ie.show_forms ()
Show all images:
puts $ ie.show_images ()
Show all objects:
puts $ ie.show_all_objects ()
Show the whole page with all frames:
puts $ ie.html ()
Click on the link Link
activation can be done through its name or direct URL When working with JavaScript, a link can be activated only by URL, or if it is a picture link, by its image tag (src, image tag). The click method is one of the standard WATIR methods for activating a link.
$ ie.link (: text, “Portfolio”). click
If the link text can change over time, but its location does not, then it will be more reliable to use the link index (use $ ie.show_links () to search for indexes of various links):
$ ie.link (: index, 20) .click
If using JavaScript, the URL (or href tag) can be used:
$ ie.link (: url, / javascript: deleteClient \ (\ d,. * /). click
Note - URLs should be encoded (spaces are expressed as% 20, etc.). You can use regular expressions, as in the example above.
Clicking on an image
Clicking on an image is not much different from clicking on a link, except for the presence of additional scr tags and alt.
$ ie.image (: name, “login.gif”). click Submit
form
Filling out and submitting the form is probably the most difficult step to complete at the site navigation stage. To do this, you need to know the names of all text fields, selection lists, or any other elements present on the form. Use ie.show_all_objects () for these purposes.
$ ie.textField (: name, “username”). set (“testuser”)
$ ie.textField (: name, “password”). set (“testpass”)
Sending is done by “clicking” on the corresponding object:
$ ie. button (: value, “Login”). click
A quick tour of common objects
Pop-up management
Actions
new, back, forward, send_keys, goto, close, refresh, minimize, maximize, restore
$ ie.back ()
$ ie.forwards ()
$ ie.send_keys (“{TAB} {TAB} {ENTER}”)
$ ie.close
$ ie.goto (“http://www.google.com”)
$ ie = IE.new ()
display functions
showFrames, show_frames, showForms, show_forms, showImages, show_images, showActive, show_active, showLinks, show_links , showAllObjects, show_all_objects, show_tables, buttons, show_spans, show_labels
$ ie.show_tables
$ ie.buttons.each {| m | puts m}
Inherited objects
frame, textField, span, row, selectBox, radio, select_list, text_field,
checkBox, button, checkbox, link, cell, form, table
$ ie.frame (: index, 1)
$ ie.textField (: name, “q”). set (“Test”)
$ ie.button (: value, “OK”). click
$ ie.link (: text, “Happy link”). click
$ ie.select_list (: name, “Day”). Select_value (“today”)
Lists of objects
checkboxes, labels, images, spans, radios, select_lists, text_fields, buttons, tables, links
$ ie.checkboxes.each {| m | puts m}
$ ie.radios.each {| m | puts m}
$ ie.links.each {| m | puts m}
Checks
getText, text, getStatus, status, getHTML, html, pageContainsText, contains_text, title
if ($ ie.text.match (“Hallo”)! = nil)
puts 'Passed!'
else
puts “Failed! '
$ ie.contains_text (“Google”)
Returns: True
Other functions
getImage, getIE, enable_spinner, set_fast_speed, enable_spinner =, wait, popup, down_load_time, getLink, set_slow_speed, getTablePart, focus, url
Text fields
Description
text name = question id = value = alt = src =
Objects
textField, text_field Recognition
Methods
$ ie.show_all_objects
$ ie.show_active
$ ie.textfields.each {| textfield | puts textfield}
Other methods
value, value =, clear, click, send, set, enabled ?, flash, html, append, getContents, focus, verify_contains
The most used methods are
value, set, append, verify_contains.
Examples
$ ie.textField (: name, “q”). Value = ”Sam”
$ ie.textField (: name, “q”). Append (“I am”)
$ ie.textField (: name, “q” ) .value
Returns: “Sam I am”
$ ie.textField (: name, “q”). getContents
Returns: “Sam I am”
$ ie.textField (: name, “q”). set (“Happy”)
$ ie.textField (: name, “q”). verify_contains (“app”)
Returns: true
Buttons
Description
submit name = btnG id = value = Google Search alt = src = Button
objects Recognition methods $ ie.show_all_objects $ ie.show_active $ ie.buttons.each {| button | puts button} Other methods value, display, click, send, enabled ?, flash, html, disabled, freeze, focus Most used methods Click Examples $ ie.button (: name, “btnG”). click $ ie.button (: name, “btnG”). value Returns: “Google Search” Links Description "name = id = innerText = Business Solutions href = http: //www.google.com/services/"
Link Objects
Recognition Methods
$ ie.show_links
$ ie.show_active
$ ie.links.each {| link | puts link}
Other methods
value, title, click, link_has_image, enabled ?, flash, html, href, src, text, focus, name, innerText, equal? Commonly
Used Methods
Click
Examples
$ ie.link (: text, “Business Solutions”). Click
$ ie.link (: text, “Business Solutions”). Enabled?
Returns: true
$ ie.link (: text, “Business Solutions”). Link_has_image
Returns: false
Remarks: the link is returned without a type if show_active or show_all_objects methods are used.
Selection Lists
Description
select-one name = logonForm: _idJsp15: 0: Question id = logonForm: _idJsp15: 0: Question value = What is your cat's name? Select_list
objects
Recognition
methods
$ ie.show_all_objects
$ ie.show_active
Other methods
option, select, value, getSelectedItems, click, enabled ?, flash, select_item_in_select_list, html, getAllContents, select_value, clearSelection
The most used methods are
select, getSelectedItems, getAlectems, getAmitems, getAmitems, getAmitems, getAmitems, getAmitems, getAtems, getAlectems
Examples
$ ie.select_list (: name, /Question/).value
Returns: “What is your cat's name?”
$ ie.select_list (: name, /Question/).getAllContents
Returns array: ["What is your favorite color?", "What is your cat's name?"]
$ ie.select_list (: name, /Question/).select_value ( "What is your cat's name?")
checkboxes
Description
checkbox name = option1 id = value = Milk alt = src =
Objects
checkbox Central
checkBox
recognition methods
$ ie.show_all_objects
$ ie The .show_active
$ ie.checkboxes.each {| checkbox | puts checkbox}
Other methods
value, clear, click, set, enabled ?, checked ?, flash, html, isSet ?, getState
Most used methods
click, set, clear, checked?
Examples
$ ie.checkbox (: name, “Milk”). Set
$ ie.checkbox (: name, “Milk”). IsSet?
Returns: true
$ ie.checkbox (: name, “Milk”). Click
$ ie.checkbox (: name, “Milk”). IsSet?
Returns: false
$ ie.checkbox (: name, “Milk”).
Clear $ ie.checkbox (: name, “Milk”). IsSet?
Returns: false
Radio buttons
Description
radio name = group1 id = value = Butter alt = src = Radio
objects Recognition methods $ ie.show_all_objects $ ie.show_active $ ie.radios.each {| radio | puts radio} Other methods value, clear, click, set, enabled ?, checked ?, html, isSet ?, getState Most used methods set, checked? (clear, carefully) Examples of $ ie.radio (: value, “Butter”). Set $ ie.radio (: value, “Butter”). IsSet? Returns: true
Note: Clear method for radio buttons is better not to use. It is better to reset the radio button by pressing another
$ ie.radio (: value, “Butter”). Clear
Frames (also known as layers)
Description
HTML Document name = message id = src = frameshop-intro.html Frame
objects Recognition methods $ ie.show_all_objects $ ie.show_frames Other methods Note: the frame behaves like a regular IE window. It can be accessed by first name (by last name), as well as by index, and usually a separate variable is created to access it. Also often frames are nested in other frames. Most used methods Examples $ f1 = $ ie.frame (: name, “message”) $ f2 = $ ie.frame (: index, 1)
$ f1.show_all_objects
The last line will return all objects in the frame, like a normal ie object.
Techniques
Pop-up handling
Thanks to a widespread client-side checker using JavaScript and other technologies, pop-ups are quite common in testing web applications.
They are divided into two types: those generated by the IE browser and those generated by the application itself.
IE usually generates pop-ups that appear only once. Take at least the Windows warning window that appears when you try to transfer unencrypted data, submit a form, or ask about remembering the password. It is recommended to block the display of such windows in IE settings and not process them in a script. JavaScript and ActiveX form their windows, requiring the user to confirm this or that action, displaying incorrect data, etc. IE does not perceive the page to be fully loaded until the javascript dialog is closed, therefore, the Ruby script will not finish its work until the dialog is closed.
This can cause a problem, since closing the window requires the previous step to work, but it cannot be completed due to the dialog box.
To prevent this situation, it is recommended that any actions that may trigger the appearance of javascript pop-ups, be performed in a separate thread. This will allow the main script to continue while another thread is waiting for the window to close.
Thread
Clicking the confirmation button to close the dialog:
Clicker = WinClicker.new
Clicker.clickJavaScriptDialog (“OK”)
Hidden Frames
Sometimes, although the show_frames function returns 0, many or even all frames on a page can be part of a hidden frame. If you are faced with a situation in which the page visually contains objects, but returns an empty list, check to see if they are in a hidden frame. Use the following command:
$ ie.frame (: index, 1) ...
This will allow you to access frames by index. The main frame has an index of 0, the second in a row, respectively 1.
Interactive script development
Once you get used to the process of writing scripts in Ruby and WATIR, you will probably find it very exhausting and time-consuming due to the lack of your own recorder. One way to dispel dull anguish is to use the built-in ruby interpreter from time to time.
The interpreter kindly provides you with the ability to debug a script line by line in an open browser. You can use the methods discussed above, such as show_links, show_all_objects to recognize objects on the displayed page, instead of running the script every time from the beginning.
An alternative is the interactive show_active_method function. It is used to recognize the object in focus at the moment.
puts $ ie.show_active ()
Tips and Tricks
Built-in substitution
Set the variable todaysDate to the current date in the format month month-year (04212006)
$ todaysDate = Time.now.strftime ("% m% d% Y")
Replace the date in the string with the current date value
pimsSQL “delete from blotter_funds where name = '# _ 1' and prime_broker = 'Bobby Brown'”
Or the same, only using string concatenation
pimsSQL “delete from blotter_funds where name = '” + $ todaysDate + "_1' and prime_broker = ' Bobby Brown '"
Link to the original article:
www.thoughtworks.com/insights/blog/creating-automated-test-scripts-ruby-and-watir