Let's consider a scenario testing Google search and use it as an example of test definition. Let's name our test 'GoogleSearch'. Name has to be upper case since it will be used as Ruby class name.
First let's assume that our 'Demo' project has been created and is properly referred in bubik.ini. The following steps of test definitions are:
Let's consider the following test scenario:
Additionally let's declare that this test belongs to test groups (aka suites) 'regression' and 'stats', and define its short description.
The example content of test file would be:
#GROUPS: regression, stats
#DESC: A tutorial scenario for google search
driver = handler( :webdriver ).driver
driver.navigate.to "http://www.google.com"
element = driver.find_element( :name, 'q' )
element.send_keys "England"
wait = Selenium::WebDriver::Wait.new( :timeout => 10 )
wait.until { driver.find_element( :xpath, "//div[ @id='resultStats' ]" ) }
stats = driver.find_element( :xpath, "//div[ @id='resultStats' ]" ).text
# stats contains something like: "About 14,700,000 results (0.61 seconds)"
# need to extract the number and convert it from string to int
num = stats.match( /([\d\.,]+\s?)+/ )[0].strip.gsub( /,|\.| / , "" ).to_i
log( "found: #{num} results" )
assert( num >= 1000 , "Number of results should be greater than 1000" )
For those familiar with WebDriver this listing looks pretty straightforward. There are only few points that require some clarification:
To execute this test and see the results in the console the following command should be used:
bubik -tGoogleSearch -rconsole
Looking at the scenario above we can see that it could be easily reused for different parameters: search term, and expected number of results. In the example there are hardcoded "England" and 1000). In order to introduce parameters to this test we need to create a CSV file which will hold parameter values, and then refer to them in test using param( 'param_name' ) function.
The CSV file has to be saved in the same directory as GoogleSearch.rb under name GoogleSearch.csv. Expected format: semicolon (;) as separator, quote as string delimiter ("), UTF-8 encoding with no BOM. And example parameters file for our test scenario could look like this:
| term | min_results |
|---|---|
| England | 1000 |
| Polska | 1000 |
| Deutschland | 2000 |
| Россия | 3000 |
Modified test that will be executed 3 times for each set of parameters (line from CSV file) should look like below. A single set of parameters (line from CSV file) is called a test variant. If there is no CSV file with parameters test has one variant (not parametrized).
#GROUPS: regression, stats
#DESC: A tutorial scenario for google search
driver = handler( :webdriver ).driver
driver.navigate.to "http://www.google.com"
element = driver.find_element( :name, 'q' )
element.send_keys param( 'term' )
wait = Selenium::WebDriver::Wait.new( :timeout => 10 )
wait.until { driver.find_element( :xpath, "//div[ @id='resultStats' ]" ) }
stats = driver.find_element( :xpath, "//div[ @id='resultStats' ]" ).text
# stats contains something like: "About 14,700,000 results (0.61 seconds)"
# need to extract the number and convert it from string to int
num = stats.match( /([\d\.,]+\s?)+/ )[0].strip.gsub( /,|\.| / , "" ).to_i
log( "found: #{num} results" )
expected_min = param( 'min_results' ).to_i
assert( num >= expected_min , "Number of results should be greater than #{expected_min}" )
As presented in the example hardcoded values have been replaced with param() function calls. Please bear in mind that values returned from this function are strings, so conversion to other types (number, bools, etc) might be needed. In the example above since value of 'min_results' is compared with an integer value in assert() call it has to be converted to integer before. Hence to_i appearing in the line above assert function call.
Looking at this example one could see that there are still another two values hardcoded: the URL of the page to start from, and the XPath expression locating text with search stats on the page. Since these values might be used in other tests as well it makes sense to extract them to some place accessible for all code related to the project. Bubik provides this features using ini files that are saves in 'const' subdirectory. Since in bigger projects list of constants can grow significantly bubik supports grouping these constants into files. For our example let's locate start URL and XPath location in separate files.
If there's only one consts file (smaller projects) it should be named default.ini. When more files come the names don't matter - they just have to be saved in the same directory as default.ini
For our example default ini will look like this (section 'common' is required):
[common]
start_url = "http://www.google.com"
For XPath locator, which is semantically connected to UI let's create file ui.ini with the following contents:
[common]
locator.stats = "//div[ @id='resultStats' ]"
Now let's use function const() to access these files in the test:
#GROUPS: regression, stats
#DESC: A tutorial scenario for google search
driver = handler( :webdriver ).driver
driver.navigate.to const( 'start_url' )
element = driver.find_element( :name, 'q' )
element.send_keys param( 'term' )
wait = Selenium::WebDriver::Wait.new( :timeout => 10 )
wait.until { driver.find_element( :xpath, const( 'ui.locator.stats' ) ) }
stats = driver.find_element( :xpath, const( 'ui.locator.stats' ) ).text
# stats contains something like: "About 14,700,000 results (0.61 seconds)"
# need to extract the number and convert it from string to int
num = stats.match( /([\d\.,]+\s?)+/ )[0].strip.gsub( /,|\.| / , "" ).to_i
log( "found: #{num} results" )
expected_min = param( 'min_results' ).to_i
assert( num >= expected_min , "Number of results should be greater than #{expected_min}" )
Please keep in mind that constants from files other than default.ini need to be referenced with file specific prefix added to constant name.
Very often it happens that one application is being tested on different environments. This might refer to different stages of development and testing (dev, integration, staging) of different localizations of our site. Let's imagine that we'd like to run out test not against google.com domain, but rather localized versions for UK, Poland, Germany and Russia. In order to do that we don't need to change neither the test script nor the parameters file. The environments are defined in const file, and referred in execution command.
In our case let's change the defaut.ini file in the way so that definition of 'start_url' would be different for different environments. The environments are defined as sections of the ini file:
[common]
start_url = "http://www.google.com"
[en]
start_url = "http://www.google.co.uk"
[pl]
start_url = "http://www.google.pl"
[de]
start_url = "http://www.google.de"
[ru]
start_url = "http://www.google.ru"
Once this file is saved the name of the environment that we'd like to use for test execution should be passed as parameter to bubik command. So to run the test for 'pl' and 'de' environments the command should look like this:
bubik -tGoogleSearch -rconsole -epl,de
Since there are 4 variants defined in CSV file and tests should be executed in 2 environments test will be executed 8 times. Each variant once per each environment.
Having multiple environment specific constants in default.ini file we might want to use them to define test variants specific to given environment. The most common scenario utilizing this feature is testing translations in internationalized websites. Let's extend our example scenario with assertion on one of page headers. It will be different for Polish, German and Russian site localizations, but using environments and CSV file we can test both three language versions without having to change the test scenario file.
Let's start from extending the CSV file with column for the translation that we expect to appear on the site, and want to assert on. Let's name this column 'search_label'. In order to associate variants (aka parameter sets, CSV rows) with environments a column '__env' has to be added. With these two columns CSV file will look like this:
| __env | term | min_results | search_label |
|---|---|---|---|
| en | England | 1000 | Search |
| pl | Polska | 1000 | Wyszukiwarka |
| de | Deutschland | 2000 | Suche |
| ru | Россия | 3000 | Поиск |
Now let's add the assertion on the search label to test script, so it looks like this:
#GROUPS: regression, stats
#DESC: A tutorial scenario for google search
driver = handler( :webdriver ).driver
driver.navigate.to const( 'start_url' )
element = driver.find_element( :name, 'q' )
element.send_keys param( 'term' )
wait = Selenium::WebDriver::Wait.new( :timeout => 10 )
wait.until { driver.find_element( :xpath, const( 'ui.locator.stats' ) ) }
stats = driver.find_element( :xpath, const( 'ui.locator.stats' ) ).text
# stats contains something like: "About 14,700,000 results (0.61 seconds)"
# need to extract the number and convert it from string to int
num = stats.match( /([\d\.,]+\s?)+/ )[0].strip.gsub( /,|\.| / , "" ).to_i
log( "found: #{num} results" )
expected_min = param( 'min_results' ).to_i
assert( num >= expected_min , "Number of results should be greater than #{expected_min}" )
search_label = driver.find_element( :xpath, "//div[ @id='ab_name' ]/span" ).text
assert( search_label.eql?( param( 'search_label' ) ), "Search labels have to matach" )
Let's run this test for 'en' and 'pl' environments using command:
bubik -tGoogleSearch -rconsole -een,pl
Unlike in previous example, where '__env' column was not set and all variants were executed as many times as many environments were passed to command, in this example each variant will be executed only once, for the environment it is assigned to by '__env' column.
That's a short introduction, please search for more information in other sections of this wiki.resultStats is compared with an integer value in assert() call it has to be converted to integer before. Hence to_i appearing in the line above assert function call.
Looking at this example one could see that there are still another two values hardcoded: the URL of the page to start from, and the XPath expression locating text with search stats on the page. Since these values might be used in other tests as well it makes sense to extract them to some place accessible for all code related to the project. Bubik provides this features using ini files that are saves in
Wiki: Configuration
Wiki: Handlers
Wiki: Home
Wiki: Project creation
Wiki: Test execution