I haven’t updated my blog in a while… sorry for that. Besides my day job, I’ve been busily working on a new open-source project that has been in my head for quite a while now and I finally decided to just go for it. I’m almost close to “announcing” it more publicly, but for right now I am gathering some feedback from colleagues before I unleash my horrifying code for the world to consume.
More later…
Here I thought I was going to have to bite the bullet and learn more than a little bit of Ruby by way of Behavior Driven Development. I thought I was going to have to actually put my head down and start active coding in Ruby in order to use the Cucumber BDD framework, specifically to parse the Given/When/Then clauses.
I thought about writing my own framework to do just that in Java, and actually started to. Then I went to the magical Google and – wouldn’t you know it? – I found JBehave. Of course! I knew Dan wouldn’t have let me down by making me go the way of Ruby
(not that there’s anything wrong with Ruby, I just like to take my sweet time drinking kool-aid
)
I love how it is just as easy to write JBehave tests as it is to write Cucumber tests:
Given a user with the email address “someone@something.com” has not already registered with the system
When a user tries to register in the system with the email of “someone@something.com”
And a name of “Michael Dowling”
And a date of birth of “1/1/1985″ (yeah right)
Then register the user with an access token of “Registered”
In JBehave, being clearly well-designed in an IoC manner, asks you write the Steps to execute the above spec:
package minderupt.scenarios.steps; 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 CreateUserSteps extends Steps { private String email; @Given("a user with the email address \"$email\" has not already registered with the system") public void checkForRegisteredUser(String email) { // code to check for pre-existing email } @When("a user tries to register in the system with the email of \"$email\"") public void registerUserWithEmail(String email) { // code to register with email } @When("a name of \"$name\"") public void registerUserWithFullName(String name) { // code to register with name } @When("a date of birth of \"$dob\"") public void registerUserWithDateOfBirth(String dob) { // code to register with DOB } @Then("register the user with an access token of \"$token\"") public void checkForCreatedUser(String tokenExpected) { // register user and confirm returned token, blah blah } }
…and then write the actual test case, specifying configuration options and the actual steps to execute during the test:
package minderupt.scenarios; import org.jbehave.scenario.JUnitScenario; import org.jbehave.scenario.Scenario; import minderupt.scenarios.steps.CreateUserSteps; public class CreateUser extends Scenario { public CreateUser() { super(new CreateUserSteps()); } }
I like this approach for multiple reasons, not the least because I can re-use the steps for different spec documents utilizing the same language, but also, I can change the test case configuration so that on my dev machine (local build) I can run all the tests and simply outputthe results to my console, but in my CI system, the output goes out to some kind of standard reporting system in pretty HTML. Yay.
Like I mentioned in a previous post, one of the things I want to do is be able to fully spec out a requirement in a document (in Word, HTML, Wiki, etc) which will have a mix of business logic rules, FIT tests, and BDD tests. Then as part of a build, split out the FIT tests and run FIT against those, parse out the BDD tests and run those, and then output a report back into the combined document for the entire team to see. Can’t be too hard, just a matter of parsing Word/HTML, recognizing the type of tests, and running them. Integration project, really.
But I think it would be immensely useful, especially for organizations that (still) communicate over such types of documentation; a behavior that I feel isn’t going away anytime soon. Might as well make the transition a little bit easier, I think.
A couple weeks ago I attended a public class led by Elisabeth Hendrickson and Dale Emery (which, btw, was aboslutely AMAZING and if you have not taken their class before, I would highly recommend that you do so). Two things stood out during that 3-day class: Elisabeth’s simulation (where we all naturally migrated to a more test-first process), and the discussion around ATDD using natural domain language.
For example:
Given a user with the email address “someone@something.com” has not already registered with the system
When a user tries to register in the system with the email of “someone@something.com”
And a name of “Michael Dowling”
And a date of birth of “1/1/1985″ (yeah right)
Then register the user with an access token of “Registered”
This executes the following Cucumber code (in Ruby):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Given /a user with the email address "(.*?)" has not already registered with the system/ do |email| @email = email end When /a user tries to register in the system with the email of "(.*?)"/ do |registerEmail| @registerEmail = registerEmail end When /a name of "(.*?)"/ do |name| @registerName = name end When /a date of birth of "(.*?)\/(.*?)\/(.*?)"/ do |dobMonth, dobDay, dobYear| @month = dobMonth @day = dobDay @year = dobYear end Then /register the user with an access token of "Registered"/ do token = RegistrationService.register @registerEmail @registerName @month @day @year if token != "Registered" raise "Not registered" end |
The neat part of this is that it is an executable document; meaning, it is input to “test fixtures” written by development to test the software being developed from an acceptance point-of-view. This is the essence of “Behavior Driven Development” or BDD, of which I am a total convert.
I want to write much more about this topic – and I will. For now, though, the one though swirling through my head is the need to have documents be in formats large organizations (such as my employer) use to describe requirements (behaviors). I doubt it will be possible for most teams to check-in plain text files and be comfortable with that. Plus, these documents will need to be passed around, possibly stored in Wikis, or other document management systems (even though ideally, these documents would be in source control along with the ATDD code).
I think I found a new project for myself. Hmmm….