Introduction¶
Behaviour Driven Development has gained in popularity in recent years. Behaviour Driven Testing allows you to create acceptance tests for your application in natural language, making it simple to use even for non-technical team members. Test cases are usually created using Gherkin syntax, which makes them easy to read. Once created, test cases can be automated using Squish.
Behave is a BDD tool which reads a Gherkin style file and applies Python code to execute it. This article demonstrates how easy it is to integrate Behave and Squish. In similar ways Squish can be integrated with other Python-based BDD tools like Lettuce or Freshen .
As an example application under test Java application AddressBook is chosen, which is shipped together with Squish. Using a similar approach, we can automate Qt, Windows, Mac, iOS, Android, Web applications.
Feature definition¶
Let us start by defining how our Feature "Filling of address book" shall behave. To do that we create a so-called feature file using the Gherkin syntax. To make it more interesting to some steps parameters were added (like "Then "0" entries should be present", "Then "2" entries should be present") and some steps are data-driven (like "When adding persons to address book")
addressbook.feature
Feature: Filling of address book
Scenario: Initial state of created address book
Given no prior existing address book
When I create a new addressbook
Then "0" entries should be present
Scenario: State after adding two entries
Given a newly created addressbook
When adding persons to addressbook
| firstname | lastname | email | phone |
| Tom | Pawlo | tom@m.com | 500600700 |
| June | Gool | jg@m.com | 100299300 |
Then "2" entries should be present
Looking at this Feature file from the Squish perspective, we can think of a Scenario as a test case and Feature as a test suite.
Next we need to actually automate these test cases with Squish. This means adding Python code with Squish and Java API to test the steps. To do that we need to create another file - steps/addressbok.py. The Python code for every step can be either recorded by Squish using Record/Playback functionality from the Squish IDE, or entered manually.
In order to run Squish test cases from a Python script we are using the Python module squishtest. More information about this module can be found in the article Using Squish as a module in other Python scripts, applications . Please remember to add the squishtest module name before every method call, as this module is not added automatically when code is generated.
from behave import *
import names
import squishtest
@given('no prior existing addressbook')
def step_impl(context):
pass
@when('I create a new addressbook')
def step_impl(context):
squishtest.activateItem(squishtest.waitForObjectItem(names.AddressBook_JMenuBar, "File"))
squishtest.activateItem(squishtest.waitForObjectItem(names.File_JMenu, "New..."))
@then('"{number}" entries should be present')
def step_impl(context,number):
assert squishtest.findObject(names.AddressBook_JTable).rowcount is int(number)
@given('a newly created addressbook')
def step_impl(context):
squishtest.activateItem(squishtest.waitForObjectItem(names.AddressBook_JMenuBar, "File"))
squishtest.activateItem(squishtest.waitForObjectItem(names.File_JMenu, "New..."))
@when('adding persons to addressbook')
def step_impl(context):
for row in context.table:
squishtest.activateItem(squishtest.waitForObjectItem(names.Address Book_JMenuBar, "Edit"))
squishtest.activateItem(squishtest.waitForObjectItem(names.Edit_JMenu, "Add..."))
squishtest.type(squishtest.waitForObject(names.AddressBook_AddForename_JTextField), row['firstname'])
squishtest.type(squishtest.waitForObject(names.AddressBook_AddSurname_JTextField), row['lastname'])
squishtest.type(squishtest.waitForObject(names.AddressBook_AddEmail_JTextField), row['email'])
squishtest.type(squishtest.waitForObject(names.AddressBook_AddPhone_JTextField), row['phone'])
squishtest.clickButton(squishtest.waitForObject(names.AddressBook_AddOK_JButton))
Next create one more file where we may define code to run before and after certain events: environment.py. Now create the function before_scenario, where we define information about the Application Under Test, Object Map and Test Results.
import squishtest
def before_scenario(context, scenario):
squishtest.setTestResult( "xml2", "results.xml" )
squishtest.testSettings.setWrappersForApplication( "AddressBook.class", ["Java"] )
squishtest.startApplication( "AddressBook.class" )
Execution¶
We just need to start squishserver and we are ready to execute our test suite. To do that simply run:
behave addressbook
Output:
Feature: Filling of addressbook # addressbook.feature:1
Scenario: Initial state of created addressbook # addressbook.feature:3
Given no prior existing addressbook # steps/addressbook.py:4 0.000s
When I create a new addressbook # steps/addressbook.py:8 1.216s
Then "0" entries should be present # steps/addressbook.py:13 0.059s
Scenario: State after adding two entries # addressbook.feature:8
Given a newly created addressbook # steps/addressbook.py:17 1.205s
When adding persons to addressbook # steps/addressbook.py:22 5.197s
| firstname | lastname | email | phone |
| Tom | Pawlo | tom@m.com | 500600700 |
| June | Gool | jg@m.com | 100299300 |
Then "2" entries should be present # steps/addressbook.py:13 0.003s
1 feature passed, 0 failed, 0 skipped
2 scenarios passed, 0 failed, 0 skipped
6 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m7.681s
Now let us see how output from our execution will look when an error in the application is found. To simulate such case the address book.feature file was modified to expect 1 entry when a new addressbook is created.
Output from execution with failures:
Scenario: Initial state of created addressbook # addressbook/addressbook.feature:3
Given no prior existing addressbook # addressbook/steps/addressbook.py:4 0.000s
When I create a new addressbook # addressbook/steps/addressbook.py:8 1.214s
Then "1" entries should be present # addressbook/steps/addressbook.py:13 0.053s
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/behave/model.py", line 1037, in run
match.run(runner.context)
File "/Library/Python/2.7/site-packages/behave/model.py", line 1430, in run
self.func(context, *args, **kwargs)
File "/Users/tomasz/behave/addressbook/steps/addressbook.py", line 15, in step_impl
assert squishtest.findObject(names.AddressBook_JTable).rowcount is int(number)
AssertionError
Additionally to output from Behave execution, for every executed Scenario, Squish results.xml
file is generated, where all Squish logs,errors and warnings can be found.
Additional notes specific to Mac OS X¶
To run tests the following environment variables need to be defined:
export SQUISH_USE_AWT=1 export SQUISH_DIR=<location of Squish> export VERSIONER_PYTHON_PREFER_32_BIT=yes export PYTHONPATH=$SQUISH_DIR/lib export DYLD_LIBRARY_PATH=$SQUISH_DIR/lib:$SQUISH_DIR/perl/lib/5.10.1/darwin-thread-multi-2level/CORE
On 64bit systems, Behave shall be run in 32bit mode, because squishtest module is 32bit. In that case, define the environment variable
VERSIONER_PYTHON_PREFER_32_BIT=yes
.