Cucumber, Selenium and Gherkin have become popular tools for helping teams implement test automation or what is often referred to as Acceptance Test Driven Development (ATDD) or Behavior Driven Development (BDD). As you grow your test suite and as it becomes larger and more complex, you may find your test project becomes bloated and messy. This article will lay out steps you can take to optimize your test organization and ways to provide unmeasured flexibility in running different tests on different browsers.
In this article, we will cover:
- 'Tagging' Tests for better organization
- 'Hook' up your tests with @Before and @After hooks
- 'Support' your test organization with the Support folder
- 'Rake' up your cucumber statements with a Rakefile
In this article series we use Ruby as the implementation language (and we recommend Ruby when there is no other existing preference). However, these examples will translate easily to other languages like Java.
If you are not familiar with Selenium, Cucumber and Gherkin take a look at our related introductory blog "The 5 Step Guide for Selenium, Cucumber, and Gherkin" and "Getting the Most out of Cucumber, Gherkin, and Selenium"1. 'Tagging' Tests for better organization
There are multiple ways for you to organize your tests, but among them Tags are some of the most versatile and powerful. While you can organize your tests by placing them in separate feature files, this only allows one level of customization. Using tags, you can annotate each test with as many tags as you feel are relevant:
@Smoke @HomePage @Past @Days @Message Scenario: Homepage allows display of message for previous days Given the user is on the message of the day homepage When the user enters a previous date that is 02/03/2002 And the user clicks the get message button Then the user sees the message of the day for a Sunday
This allows you to tag a test with numerous types of tags, for instance marking certain tests as @Regression or @Smoke tests, or tagging numerous tests across multiple features with what specific functionality they test, for instance you could have tests tagged as @Smoke across multiple feature files. You can even tag an entire feature if you all the scenarios to have the same tag.
The power of tags comes in when you go to run your tests. By specifying one or more tags as command line options, you can run sets of tests covering a wide range of needs. The example below demonstrates how to run any tests tagged with @Smoke AND @HomePageTest
$> cucumber ENVIRONMENT=dev BROWSER=chrome --tags @Smoke --tags @HomePageTest
You can also run tests tagged with @Smoke OR @HomePageTest
$> cucumber ENVIRONMENT=dev BROWSER=chrome --tags @Smoke,@HomePageTest
2. 'Hook' up your tests with @Before and @After hooks
Hooks are one of the most important features when optimizing your Selenium tests. The basic concept is that a hook runs before or after a scenario, the most common application is to use a Before hook to spin up your driver and even navigate to your application, then use an after hook to tear down after the scenario is completed. Here is a simple example of how you can use hooks in your project
Before do |scenario| puts 'Executing scenario: ' + scenario.name $config = eval(File.open('options.config') {|f| f.read }) $url = $config[:config_url_dev] $driver = Selenium::WebDriver.for :chrome $wait = Selenium::WebDriver::Wait.new(:timeout => 5) # seconds end After do |scenario| $driver.quit end
You can even create specific hooks which only execute if the scenario contains a matching tag. For instance:
Before('@HomePageTest') do |scenario| puts 'Special homepage tagged hook' end
This just scratches the surface of the power of hooks. Hooks are often used to perform data setup and teardown - allowing us to create the data expected to be present by the test - and cleanup the data after the test. You can also declare hooks which run only once each time you spin up the tests, or declare hooks which run before or after each step. For more information on cucumber hooks, see this article https://github.com/cucumber/cucumber/wiki/Hooks
3. 'Support' your test organization with the Support folder
If you inherited an existing Selenium project, you may have noticed a folder underneath your features folder named "support". In many projects, you will find files called hooks.rb and env.rb. This is a structure you can use in your project to centralize shared steps. If the folder does not exist in your project, you can manually add it and empty ruby files. Note that you do not have to use these specific names; any files in the support folder will be loaded.
- env.rb - Use this to centralize all of your "require" statements, this way they are only loaded once and do not clutter your steps file. This is also a good place to put shared functions and static variables.
- hooks.rb - This file is where you can centralize you’re your before and after hooks. This is a great step to centralizing shared logic, such as connecting to your application.
By moving all shared logic to these files, your ruby step files will start to look much less cluttered and be easier to manage.
4. 'Rake' up your cucumber statements with a Rakefile
Using the techniques above, your test project is now flexible and adaptable, assuming you know the exact cucumber statements you need to run. But this can be a challenge if you want to run a specific set of tags on the fly, or if you want to run tests on a certain browser. To make life simpler, we have found organizing your project with a Rakefile to make it easier to run your tests without needing to spend a lot of time crafting cucumber statements.
Rake is a build language which is based off Ruby. If you want to use Rake, run the terminal command gem install rake and then create a file with no extension named Rakefile and begin editing. Using Rake, you can create a set of tasks to run specific sets of tests:
task :run_dev_chrome_homepage do cucumberStatement = 'cucumber ENVIRONMENT=dev BROWSER=chrome --require features features/homepage.feature' sh(cucumberStatement) do |success, _exit_code | @success &= success end end
And then run the tests using the following terminal command when in the same directory as your Rakefile:
$> rake run_dev_chrome_homepage
One of the most powerful uses we have found in using a Rakefile is adding parameters to the tasks. This allows you to run a huge range of test sets simply and without needing to craft length cucumber statements each time
task :run_tests, [:environment, :browser, :tags, :feature, :scenario] do |t, args| cucumberStatement = 'cucumber ENVIRONMENT=' + args[:environment] + ' BROWSER=' + args[:browser] if (!args[:tags].nil? && !args[:tags].empty?) splitTags = args[:tags].split ' ' splitTags.each do |singleTag| cucumberStatement += ' --tags @' + singleTag end elsif (!args[:feature].nil? && !args[:feature].empty?) cucumberStatement += ' features/' + args[:feature] + '.feature' elsif (!args[:scenario].nil? && !args[:scenario].empty?) cucumberStatement += ' features --name "' + args[:scenario] + '"' end puts cucumberStatement sh(cucumberStatement) do |success, _exit_code | @success &= success end end
And execute the rake task with the following terminal command:
$> rake run_tests['dev','chrome','HomePage Smoke']
There is much more you can do with Rake, and there are numerous syntaxes you can use to create your Rakefile. To learn more, read through the Rake README here: https://github.com/ruby/rake.
Using these four techniques, you will be able to organize your tests and find easy ways to run specific test scenarios as needed, as well as have a range of pre-established test sets which are easy to schedule or run ad hoc.
To become an ICAgile Certified Professional in Agile Testing or to learn more about automation and Agile testing check out our courses.