This post is about JBehave and how to quickly get started with it. If you would like to know about BDD please use the following link.
What is Behavioral Driven Development?
Today I have used JBehave for the first time. It does have some convincing factors for instance diving requirements into scenarios which map pretty nicely to the tests that are written with in the Steps. Thus it seems like it would be easier for Stakeholder/s to use it as a good guideline for the initial requirements. Its always quite usual to come up to some disagreements about the development however the tool does help to bring forth the ease for stake holders who really dont have to get into writing code but will have a technical jargon to communicate through to the developers in shape of scenarios.
So the first things come up.
1. Create a Java project in Eclipse.
2. Download the JBehave latest version from the website and add the jar files to your project build classpath
3. Create a scenario file and name it as user_wants_to_shop.scenario
Add the following text to the file
1 2 3 | Given user Shaaf is logged in
Check if user shaaf is Allowed to shop
Then show shaaf his shopping cart |
The lines above simply state the rules for the scenario we are about to create.
4. Now we will create a java file mapping to it.
Create a new class with the name corresponding to the same as the .scenario file
UserWantsToShop.java
Add the following code to it
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import org.jbehave.scenario.PropertyBasedConfiguration; import org.jbehave.scenario.Scenario; import org.jbehave.scenario.parser.ClasspathScenarioDefiner; import org.jbehave.scenario.parser.PatternScenarioParser; import org.jbehave.scenario.parser.ScenarioDefiner; import org.jbehave.scenario.parser.UnderscoredCamelCaseResolver; public class UserWantsToShop extends Scenario { // The usual constructor with default Configurations. public UserWantsToShop(){ super(new ShoppingSteps()); } // Mapping .scenario files to the scenario. This is not by default. public UserWantsToShop(final ClassLoader classLoader) { super(new PropertyBasedConfiguration() { public ScenarioDefiner forDefiningScenarios() { return new ClasspathScenarioDefiner( new UnderscoredCamelCaseResolver(".scenario"), new PatternScenarioParser(this), classLoader); } }, new ShoppingSteps()); } } |
5. Just that we now have steps we need some place to put the logic for the Steps in the Scenarios. So we create a new Steps class ShoppingSteps.java
1 2 3 4 5 6 7 8 | import org.jbehave.scenario.annotations.Given; import org.jbehave.scenario.annotations.Then; import org.jbehave.scenario.annotations.When; import org.jbehave.scenario.steps.Steps; public class ShoppingSteps extends Steps { } |
6. Now you can run the Scenario by running it as a Junit Test.
Following should be the output
1 2 3 4 5 | Scenario: Given I am not logged in (PENDING) When I log in as Shaaf with a password JBehaver (PENDING) Then I should see my "Shopping Cart" (PENDING) |
This means that none of the scenario requirements have been implemented as yet. But the test result should be green to show there are no problems with our setup.
Now lets add the implementation to the tests.
7. Add the body to the ShoppingSteps. I have added the comments with the methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // Given that a user(param) is loggen in @Given("user $username is logged in") public void logIn(String userName){ checkInSession(userName); } // Check if the user is allowed on the server @When("if user $username is $permission to shop") public void isUserAllowed(String userName, String permission){ getUser(userName).isUserAllowed().equals(permission); } // finally then let him use the shopping cart. @Then("show $username his Shopping cart") public void getMyCart(String userName, String cart){ getUserCart(userName); } |
8. Now you should try to run the scenario again. And all of the test should be green. I have not implemented the actual methods so they will be red.
Tags: Java, jbehave, unit testing
Alot of times I have seen the questions popping up whether to use isDebugEnabled property or not. Arguably most of the times or rather always about performance. Some of the stuff that I feel important about using it follows.
The answer is simple. It is made to be used. However using it has to be with caution.
For instance
If I am using the following line in my code.
1 | log.debug("I am there"); |
Thats an example of a good practise
However I can really blow it out of proportions if I do the following.
1 2 3 4 | // Not good practise if (log.isDebugEnabled()){ log.debug("I am there"); } |
And why exactly is that so. This is because the method debug in the class Category i.e. extended by Logger in the log4j libraries explicitly checks the mode for the logging itself.
Extract from the class org.apache.log4j.Category is below
1 2 3 4 5 6 7 | public void debug(Object message) { if(repository.isDisabled(Level.DEBUG_INT)) return; if(Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) { forcedLog(FQCN, Level.DEBUG, message, null); } } |
Okay so thats the case where we say dont use it. What about the one where we actually do use the isDebugEnabled property.
For instance you have a large parameter going in the debug.
1 2 | // Bad Practise log.debug("XML "+Tree.getXMLText()); |
In such a case it can clearly be said “No dont do it!” If Tree.getXMLText is going to pull out all the hair out of the app then there is no use. As it will be constructed first and if the debug level is not enabled that would be a performance cost.
1 2 3 4 | // Good Practise if (log.isDebugEnabled()){ log.debug("XML "+Tree.getXMLText()); } |
Thus in the example above it would be wiser to use log.isDebugEnabled() just to make sure the mileage or cost stays lesser.
Tags: best practise, Java, log4j, logging, Programming
What is Selenium
How does Selenium work
History and how it started
About Ant
And Junit
Much of the technologies above do not or will not need an introduction if you already know them or can read them from the links above.
More over today’s article is more about how we can use all the three selenium, ant and junit to come up with an automated solution for regressive testing.
Please refer to the documentation links above for the basic knowledge on any of the used tools.
I am assuming that you know how to record a test in selenium if you dont then go here
Now that you do know how to record and save the tests simply save them in any directory structure you like as long as they follow the right package convention. like com.foo.bar
this would mean the file should be in directory like com/foo/bar. Conventionally and logically today that is how the TestCase is compiled through the ant script. If the package is not the right path then compile time errors will occur.
My calling target for running the whole procedure should look like this
< target name="build_tests" depends="clean, compile, start-server, tests, stop-server" / >
Details of the depending targets are as follows.
clean: would clean the entire build directories etc to make sure nothing from our past is carried forward into the future.
compile: should compile
start-server: should start the selenium server.
tests: should run the selenium tests.
stop-server: should stop the selenium server once all tests have been executed.
How to start a selenium server from Ant?
< target name="start-server" >
< java jar="lib/selenium-server.jar" fork="true" spawn="true" >
< arg line="-timeout 30" / >
< jvmarg value="-Dhttp.proxyHost=proxy.proxyhost.com" / >
< jvmarg value="-Dhttp.proxyPort=44444" / >
< / java >
< / target >
The target above is simply taking the selenium-server.jar which is in the classpath and running the main-class from it. the proxy parameters are optional.
How to stop the server from Ant?
< target name="stop-server" >
< get taskname="selenium-shutdown"
src="http://localhost:4444/selenium-server/driver/?cmd=shutDown"
dest="result.txt" ignoreerrors="true" / >
< echo taskname="selenium-shutdown" message="DGF Errors during shutdown are expected" / >
< / target >
The selenium server starts on port 4444 by default and to tell it to shutdown is simple, the command in the src is passed to it. cmd=shutDown
That should just shutdown the server.
Executing the test cases?
Selenium Test cases are Junit tests cases and that’s how they are treated in this tutorial.
Thus some of you will be very much familiar with the ant targets junit and junitreport. However I will describe how the following is working.
the following target will run the selenium tests and print a summary report to the ${dir}
The includes and excludes, simply tell the target which files to include or exclude while running the test cases. This is typically done when you don’t want some tests cases to be included or your source for tests and the application are in the same directory and you only want to include something like Test*.class.
< target name="tests" depends="compileonly" description="runs JUnit tests" >
< echo message="running JUnit tests" / >
< junit printsummary="on" dir=".." haltonfailure="off" haltonerror="off" timeout="${junit.timeout}" fork="on" maxmemory="512m" showoutput="true" >
< formatter type="plain" usefile="false" / >
< formatter type="xml" usefile="true" / >
< batchtest todir="${testoutput}" filtertrace="on" >
< fileset dir="${src}" >
< includesfile name="${tests.include}" / >
< excludesfile name="${tests.exclude}" / >
< / fileset >
< / batchtest >
< classpath >
< pathelement path="${classes}" / >
< pathelement path="${build.classpath}" / >
< / classpath >
< / junit >
The following will take the formatted output from the lines above and generate a report out of it in xml and html and place the results in the ${reports}/index.html
A sample Junit test report might look like this.
< echo message="running JUnit Reports" / >
< junitreport todir="${reports}" >
< fileset dir="${reportdir}" >
< include name="Test*.xml" / >
< / fileset >
< report format="frames" todir="${reports}" / >
< / junitreport >
< echo message="To see your Junit results, please open ${reports}/index.html}" / >
< / target >
In general you can add all of this to your nightly build through any of the CI servers like Cruise Control. Also as a general practice you will need to do a little more then just executing this target every night depending on your application. For instance cleaning up of resource centers like Databases etc.
Tags: ant, automated-testing, build, CI, continous, engineering, integration, Junit, scm, selenium, Software, testing