Behavior Driven Design in OpenMRS
This page is little related with the wiki page https://openmrs.atlassian.net/wiki/display/docs/Testing+Releases which explains about how to have a safety check during releases.
What is BDD
Behavior Driven Design is an agile software development technique, which uses the terminology focused on behavioral aspects of the system in a profound Domain Specific Language rather than cryptic technical language which will be only understood by developers. BDD aims to bridge the gap between the different views of computer systems held by Business users and Technologists. It is deeply rooted in the success of TDD and is influenced by ideas like Domain Driven Design
BDD relies on the use of a very specific vocabulary to minimize miscommunication and ensure that everyone – the business, developers, testers, analysts, and managers – are not only on the same page but using the same words.
You can find more details on BDD in the following links
Wikipedia - http://en.wikipedia.org/wiki/Behavior_Driven_Development
Why do we need BDD
BDD itself enforces us to write scripted browser tests where the functionality can be tested as a feature. Running the scripted browser tests on regular basis will help us in finding defects on functional flow of the web application.
More details around why we need BDD can be found in the following links
Dan North blog - http://dannorth.net/introducing-bdd/
Infoq presentation - http://www.infoq.com/presentations/bdd-dan-north
How to write BDD tests
Irrespective of any language/framework, BDD tests will follow similar pattern. We will have set of stories which are written in the format of [Given, When, Then]. These stories are mapped to appropriate steps(original test code is written in steps).
change_a_global_property.story
GivenStories: org/openmrs/stories/go_to_admin_page.story
Given I am on Admin page
When I click on the Advanced Settings link
Then take me to Advanced Settings Page with Advanced Settings as heading
When I type Test1 as name
When I type Test2 as value
And I click on Save button
Then display message Global properties saved
How to write BDD tests in the context of OpenMRS
OpenMRS uses a Jbehave as the BDD tool to write Behavior driven tests. All the BDD tests are written under the module by name release-tests.
Writing and executing a story
All the OpenMRS releases post 1.9 can use Jbehave tests. Lets start with a simple example of writing a story to login to the OpenMRS website. You can see the below code in OpenMRS core at “trunk/release-test/src/main/resources/org/openmrs/stories/login_to_website.story”
You need to write a story, which is nothing but some textual representation of the functional feature you are about to test. So, in the example of login_to_website.story, we are testing whether user is able to login into the website.
login_to_website.story
Given I am on the login page of OpenMRS with url http://localhost:8080/openmrs
When I enter username and password as stored in system properties as openmrs_username and openmrs_password and click the 'Log In' button
Then take me to the Home screen and display welcome message for user Super
Jbehave automatically matches the textual story filename to the appropriate java class. In this context name of the java class Jbehave auto matches is LoginToWebsite.java . This java file in turn calls another java file with name LoginSteps.java. This steps file have functions with annotation of @Given, @And/@When , @Then. Jbehave uses a regex pattern to auto match .story file features to one of the annotations in Steps file.
Ex: The feature “Given I am on the login page of OpenMRS with url http://localhost:8080/openmrs” is matched with method onLoginPage(String url) which have the annotation “@Given("I am on the login page of OpenMRS with url $url")” . We can see that “$url” is parameterized and sent as an argument to the onLoginPage(String url).
Assuming we are already running an OpenMRS webserver at 8080 port, when running the above test, Jbehave will by default launch the firefox browser and hits the specified url and do the required operations specified in the .story file.
Jbehave uses Webdriver in the background to launch the browser and run the scripted tests. Webdriver provides lots of hooks to interact with browser using java api. Ex: Interacting with HTML DOM, interacting with specific element on the browser using xpath, using the ajax elements on the browser.
How to execute BDD tests in OpenMRS Core
From here onwards I will be using the term release-test for BDD tests. In the context of OpenMRS, release tests can be run in four different ways under four different maven profiles. Each of these profiles have there own importance.
integration-test
smoke-test
start-test-server
smoke-test-without-server* *
Maven Profile “integration-test”:
It is always better to separate release test database with the development database. Though we can run Jbheave tests over the development database, I strongly suggest running them on the release test database, so that you’ll not lose any of your dev specific data.
For the first time when you are running release-tests you can run release-tests.sh by editing the credentials as required in the file ‘release-tests.sh’ or use the below maven command which will create the release-test database and execute the release tests. This entire process will take 10 to 15 minutes for the first time as it creates and populates the database with demo data.
Running integration tests
mvn integration-test -P integration-test -q -DskipTests -Dmysql_username=<mysql_username> -Dmysql_password=<mysql_password> -Dmysql_port=<mysql_port> -Dtest=* -Ddatabase_name=<database_name>
The above maven command or release-tests.sh will setup a release test database with the name of the variable “openMRSVersion” configured in your pom.xml under release-tests module and then runs the tests. You can find more details in your .OpenMRS folder under root/app data folders.
Maven Profile “smoke-test”:
This maven profile runs the specified tests on the release-test database, provided that you’ve already created the release-test database using the profile “integration-test”. When you use this profile to run a test, it start the server by connecting it to the release-test database and executes the specified tests. Make sure you've ran integration-test profile before you ran smoke-test because the integration-test profile will help in establishing the database and corresponding properties file.
Maven command for the same is as follows.
To run the story login_to_website.story
To run all the tests in release-tests use the command
Maven Profile “start-test-server”:
Profile “smoke-test” will start the server every time you run the tests. It takes couple of minutes to start the server. To make the development of the test stories fast, we can use the profile “start-test-server”. This profile will start the application on port 8080 by connecting to release-test database.
Use the following command under release-tests folder.
To run the server which connects to release-test database
One other major advantage of running the test server is, when we have any new migrations to be run on the release tests database, current automation framework will not execute these migrations by default. You need to manually execute the migrations by starting the test server and login into the OpenMRS website.
Maven Profile “smoke-test-without-server”:
This maven profile comes very handy when you are developing the test stories. This profile will run the jbehave tests assuming that server is already started. So, the prerequisite to use this command is, OpenMRS application is running at the port 8080. So it is always advisable during the development of the stories to run the test server using the profile “start-test-server” and leave it running. Later we can use the profile “smoke-test-without-server” during the development of the stories.
to run all the release-tests (which will not run the server)
How to write and Execute BDD tests in OpenMRS modules
To write release tests (jbehave) in modules, you need to create a module by name release-tests. Currently there is no automated way to create the release-test pom.xml with correct dependencies. For now, we can use the base version of htmlformentry modules pom.xml file and make the necessary changes. In the near future we should be able to create a maven archetype, which will create the appropriate pom.xml for release tests.
Two main properties, which we need to configure appropriately in the release-test pom.xml, are “openMRSVersion” and “openMRSReleaseTestVersion”.
“openMRSVersion” will help to download the appropriate version of OpenMRS, on top of which the module will be deployed. “openMRSReleaseTestVersion” will help to download the appropriate version of release-tests jar to reuse most of the release test infrastructure.
Create appropriate package structure, which will comply with the OpenMRS core release-tests.
For more examples on how to write release tests in OpenMRS modules please look at htmlformentry module in github.
Three main maven profiles under release test maven module are
integration-test
smoke-test
start-test-server
Maven Profile “integration-test”:
This is very similar to the “integration-test” profile of OpenMRS core. Using this profile in the OpenMRS module will download the appropriate version of OpenMRS, creates the release test database, install the current module and starts the jetty web server. You can specify the OpenMRS version you want to use with this module using the parameter “openMRSVersion”. Command will look as follows.
You can also run the release-test.sh script , under release-tests module by updating the details as required.
If you have already created the release-test database for some specific openmrs version using OpenMRS core, you need not run the profile integration-test again under openmrs-module.
Ex: If you have run the integration-test profile under OpenMRS core for openmrs version 1.10.0-SNAPSHOT, you need not run the integration-test again under the openmrs module release tests. Any ways it will not create/update/destroy the database if it is already existing.
Maven Profile “smoke-test”:
This profile is very similar to “somke-test” profile of OpenMRS core. Provided that the release-test database is already created, it will start the OpenMRS core web application by installing the current module. Later all the Jbehave tests will be executed. Command for the same looks as follows.
Maven Profile “start-test-server”:
This profile starts the openmrs application, installs the current module into the server and connects to release test database. This profile comes very handy during the development of the stories (release tests), as you need not start the server each and every time you want to test your story changes. As the current implementation doesn’t support auto run of the migrations, when ever you have new set of migrations, you need to run them manually on the release test database using this profile.
Next Steps
There’s huge room for improvement in many areas of release-test infrastructure. Below are some of the areas which needs immediate concentration.
Entire release-testing module is not yet hooked up with CI. This should be done on high priority
Auto running of the new database migrations
Many of the configuration parameters (like usernames and passwords) could be fetched from the properties file.