Very recently, cucumber-jvm 1.0 was released, providing a Java implementation of the Cucumber B.D.D. test framework. Jython is one of many languages supported by this new implementation. This brief HOWTO explains how to add the cucumber-jvm jar to a Jython installation and use it to drive your specifications. Any libraries in your Jython environment will be available for your step definitions.
This assumes you have first installed Jython
I have created an environment variable for my Jython install path in ~/.bash_profile, which will be used throughout this HOWTO:
export SYS_JYTHON_INSTALL="/Users/stephenabrams/tools/jython2.5.2"
Installation
Download and run ez_setup.py to install setuptools:
~$ wget http://peak.telecommunity.com/dist/ez_setup.py
~$ jython ez_setup.py
Install pip:
~$ which jython # shows jython install location
~$ sudo jython $SYS_JYTHON_INSTALL/bin/easy_install pip
Install virtualenv:
~$ sudo jython $SYS_JYTHON_INSTALL/bin/pip install virtualenv
Create a virtual environment for a Jython project. Do the following from a location where you’d like to store your virtual environment’s libraries. This will take care of installing setuptools and pip in your virtual environment automatically.
~$ jython $SYS_JYTHON_INSTALL/bin/virtualenv jython-cucumber-jvm-example
Activate the virtual environment, ensuring library installations will be placed in the it alone:
~$ source jython-cucumber-jvm-example/bin/activate
~$ which jython # this should now point to the virtual env version of jython
Install jip to the virtual environment:
~$ which pip # sanity check, this should be virtual env pip
~$ pip install jip
Finally, install cucumber-jvm from Maven:
~$ jip install info.cukes:cucumber-jython:1.0.1
Take a peek at the jython-cucumber-jvm-example environment configuration directory to see how the cucumber-jvm jars were included.
Example Usage
Lets create a new project, and locations for our specifications and step definitions:
~$ cd workspace
~/workspace$ mkdir hello_world; cd hello_world; mkdir features; mkdir features/step_definitions; mkdir src
Create a utility Jython script for running our features called hello_world/cucumber-jvm.py:
#!/usr/bin/env jython
import sys
from cucumber.cli import Main
Main.run(sys.argv[1:], Main.getClassLoader())
For our first feature, open features/hello_world.feature and write:
Feature: Good old Hello World
Scenario: Someone starts their day
Given a person
When that person wakes up
Then that person says "Hello, World!"
Now let’s see it run. We use “jython-all” instead of jython to include the cucumber jar files installed with jip. Note that we don’t have any step definitions in features/step_definitions/ or code to test in src/ yet, but we’ll specify the “glue” code path for later:
~/workspace/hello_world$ jython-all cucumber-jvm.py --glue features/step_definitions --glue src features
You should now see some messages about the processing of the jars, and then the standard Cucumber output where the step definitions are missing:
*sys-package-mgr*: processing new jar, '/Users/stephenabrams/jython-cucumber-jvm-example/javalib/cucumber-core-1.0.1.jar'
*sys-package-mgr*: processing new jar, '/Users/stephenabrams/jython-cucumber-jvm-example/javalib/cucumber-html-0.2.1.jar'
*sys-package-mgr*: processing new jar, '/Users/stephenabrams/jython-cucumber-jvm-example/javalib/cucumber-jython-1.0.1.jar'
*sys-package-mgr*: processing new jar, '/Users/stephenabrams/jython-cucumber-jvm-example/javalib/gherkin-2.9.3.jar'
UUU
You can implement missing steps with the snippets below:
@Given('^a person$')
def a_person():
# Express the Regexp above with the code you wish you had
raise(PendingException())
@When('^that person wakes up$')
def that_person_wakes_up():
# Express the Regexp above with the code you wish you had
raise(PendingException())
@Then('^that person says "([^"]*)"$')
def that_person_says(arg1):
# Express the Regexp above with the code you wish you had
raise(PendingException())
Great success! Now lets copy these steps and put them in features/step_definitions/steps.py and run it again. We now see:
Traceback (most recent call last):
File "/cucumber/runtime/jython/dsl.py", line 34, in execute
TypeError: a_person() takes no arguments (1 given)
Interestingly, The Jython steps require “self” to be the first arg but the snippet generator doesn’t include it. Maybe this is a bug in the new framework, but for now lets just add “self” to each step def:
@Given('^a person$')
def a_person(self):
# Express the Regexp above with the code you wish you had
raise(PendingException())
@When('^that person wakes up$')
def that_person_wakes_up(self):
# Express the Regexp above with the code you wish you had
raise(PendingException())
@Then('^that person says "([^"]*)"$')
def that_person_says(self, arg1):
# Express the Regexp above with the code you wish you had
raise(PendingException())
Now we run again:
P--
cucumber.runtime.PendingException: TODO: implement me
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
...
Here an exception is thrown since these are still pending steps (stack trace truncated above). Let’s update the step definitions with some assumptions about our Person class interface:
@Given('^a person$')
def a_person(self):
self.person = Person()
@When('^that person wakes up$')
def that_person_wakes_up(self):
self.last_response = self.person.wake_up()
@Then('^that person says "([^"]*)"$')
def that_person_says(self, arg1):
if (arg1 != self.last_response):
raise(Exception("person said '%s' not '%s'" % (self.last_response, arg1)))
And let’s create the class under test:
class Person:
def wake_up(self):
return "Hit the snooze!"
And run again. Now Cucumber reports back:
..F
Traceback (most recent call last):
File "/cucumber/runtime/jython/dsl.py", line 34, in execute
File "steps.py", line 12, in that_person_says
Exception: person said 'Hit the snooze!' not 'Hello, World!'
Ahem… lets fix Person:
class Person:
def wake_up(self):
return "Hello, World!"
The next run passes, yielding three green dots.
I have also tested and verified that modules included in the Jython Lib directory are accessible from both the code under test and the step definitions.
Sources:
http://www.jython.org/jythonbook/en/1.0/appendixA.html#setuptools
http://stackoverflow.com/questions/6787015/how-i-install-various-python-libraries-in-jython
http://pypi.python.org/pypi/virtualenv
http://packages.python.org/django-jython/quickstart.html
https://docs.djangoproject.com/en/dev/topics/db/models/#quick-example
http://pypi.python.org/pypi/jip