Cucumber test engine (Ruby)

@ We, 14 October 2009, 17:13

Very often test automation solution becomes so complex that test development require quite strong programming skills. At the same time most of the solutions has a trend to simplify test automation. This can be achieved by various wizards, approaches introduction and devekopment of engines implementing these approaches. In particular,there\'s quite popular approach named keyword-driven testing where tests are actually tthe sequence of keywords structured in tabular form. But there\'s more quirky approach when test instructions are written using "natural" language with corresponding programming implementation. For instance, there\'s engine named Cucumber for Ruby. All required information may be found on http://www.cukes.info but at the moment we\'ll stop on basics.

So, let\'s say we have some test scenario like:


  • Login into the system
  • Click on "Search" button
  • Search screen is displayed



Just to clarify, the test scenario is imaginary. We operate with some "spherical application in vacuum" which has login functionality as well as some search module.

Let\'s say, this scenario has the following automated implementation on Ruby:

app.login
app.click_button "Search"
assert app.search_screen_displayed? , "No search screen available"



We base on assumption that all functionality required for this scenario has already been developped. So, we can implement this scenario in such compact way as displayed above. But this code may seem bu be easy for Ruby developers.But what if we have test-designer who simply creates test scenarios? What should be done to write the "natual language" test scenarios which can be executed automatically as is? These are the things the Cucumber does.

What is it? Actually, it is text parser operating with "natural language" text constructions and set the correspondence between each particular text statement and its implementation on Ruby. This engine is just another Ruby gem which can be installed by the following command line (rubygems version 1.3.5):

gem install cucumber

OK, according to definition we have some "natural language" text representation of the test and some Ruby code modules set into correspondence to text statements. So the distribution between definition and implementation takes place. In Cucumber it is expressed in test definition storage in files with *.feature extension while the implementation is stored in files with *.rb extension. Even more, files are stored in some fixed folder structure. Generally speaking, Cucumber operates with the folder structure built according to the following rules:


  1. Base folder containing test definitions and their implementations is named  features. It is the folder and all its sub-folders which contain feature-files
  2. All Ruby-implementations are located under features/step_definitions sub-folder and all its sub-folders
  3. Auxilary functionality is located under sub-folder named features/support
  4. features/support sub-folder also contains env.rb file which is responsible for functionality being executed before and after tests, additional settings or so. But this is another topic.
So, once we defined the structure we can create the definition of our test. In the features folder let\'s create sample.feature file and write the following definition:
Feature: Cucumber sample testing
Scenario: Sample scenario
Given Login into the system
When Click on "Search" button
Then Search screen is displayed



This is an example of Cucumber test definition. 5 "magic" keywords are highlighted with the bold (this is not complete set of keywords to be used but these are one of the most frequent ones):


  • Feature: - used for some test scenario group definition
  • Scenario: - preceeds the test name
  • Given - means that the instruction after this keyword is some pre-condition or pre-setup
  • When - means that instruction after this keyword is some action to be performed during the test
  • Then - usually preceeds the instructions responsible for various verifications



Now let\'s add the implementation of the steps above. In the features/step_definitions sub-folder let\'s create sample.rb file and fill it in with the following code:

require \\\'test/unit/assertions\\\'

World(Test::Unit::Assertions)

Given "Login into the system" do
app.login
end

When "Click on \\\\"Search\\\\" button" do
app.click_button "Search"
end

Then "Search screen is displayed" do
assert app.search_screen_displayed? , "No search screen available"
end



That\'s all. The sample is ready. Let\'s start it. Cucumber tests are executed by the command line like:

cucumber <features_folder>

Let\'s move to the folder which is parent to  features folder containing our test definitions and start the command line like:

cucumber features

Test execution will start. All executed steps will be printed out into console by default( there are various types of Cucumber output formats but they should be described separately). Well, that\'s how it works.

At the end, let\'s add some flexibility into the code. As it\'s seen from the example the instruction like

app.click_button "Search"

is supposed by design to click on button specified by the text. In other words if we need to press the button with text e.g.  "Select" we need to write something like

app.click_button "Select"

In case we work with Cucumber we need Given-When-Then statements to accept parameters in order to provide required flexibility. And it is possible. Actually Ruby implementations of Given-When-Then statements accept rather regular expression that simple string. This regular expression is some kind of pattern which should match to some text in feature file. Once pattern matches the code inside each particular implementation is executed. So, we can use not only complete string matches but also matches by pattern. For instance, instead of  "Click on \\\\"Search\\\\" link" we can use /Click on "(.*)" link/.

What we get from this? Firstly, such pattern gives the ability to use single implementation for wide range of test definition instructions varying just some sub-string (e.g. in cases when only button name varies). Secondly, Cucumber uses back-links which are passed to Given-When-Then Ruby implementations as parameters. In other words the implementation we describe can be re-written in the following way:

require \\\'test/unit/assertions\\\'

World(Test::Unit::Assertions)

Given "Login into the system" do
app.login
end

When /Click on "(.*)" button/ do |button|
app.click_button button
end

Then "Search screen is displayed" do
assert app.search_screen_displayed? , "No search screen available"
end



Updated code is highlighted with the bold.

This is just basic features overview. Actually Cucumber is quite powerful engine with wide range of features providing the ability to create the automated tests even for people who is not familiar with any programming language. The main thing is to develop all required instructions with corresponding implementations in order to build the tests using the instructions like a bricks.

You must be logged in to post comments