Monday, June 17, 2013

Cucumber Testing Goodies: Date Language and Chronic

If you've worked with Cucumber for even a short period of time you've almost certainly run up against the question of how to deal with dates and times in your gherkin.  There have been various attempts at working with dates/time in gherkin, a majority of which end up creating brittle and difficult to maintain tests.  You could hard-code dates and times, but we all know that is a bad idea, not to mention unmaintainable in the long run.   Furthermore, one of the reasons for using Cucumber is to record user stories in plain English. Lets consider an example scenario and some gherkin which may end up causing trouble down the road:

Scenario: Scheduling a 90-day Review
Given an employee is hired 3/17/2013
When I schedule a review
Then the review should be scheduled for 6/17/2013


In this scenario we are hard-coding dates, which will cause us headaches when we go to maintain this code down the road. A more maintainable scenario which uses plain English could read like this:

Scenario: Scheduling a 90-day Review
Given an employee is hired "today"
When I schedule a review
Then the review should be scheduled for "90 days from today"


You may be thinking "What's the big deal? 'Today' (or 'yesterday', or 'tomorrow' for that matter) is easy to parse out, and I bet I could whip together a little helper method to get the right date for "90 days from today" Done and done. Or is it?

Simple rolling dates such as "yesterday" or "tomorrow" may not be too difficult to work with as you can just subtract or add a day to the current date, but what about more complex dates?  Complex dates described in natural language such as "five months ago" and "second Tuesday July 2014" pose more of a challenge, and rolling your own date parsing logic is almost never a good idea, not to mention almost certainly out of scope for the problem you're trying to solve.  

So given that hard-coding is out the question, rolling your own parser is out of scope, and we want to encourage natural language in our gherkin how do you handle these kind of dates? Enter the Chronic gem.

Chronic

The Chronic gem is a natural language date/time parser for Ruby.  Because it parses phrases such as the ones described above you can incorporate English language phrases into your gherkin which can be easily parsed out in your step definitions.  Lets examine what the step definitions for our example above using Chronic look like:


Scenario: Scheduling a follow-up appointment after a sale
Given(^an employee is hired "(.*?)"$/) do |hire_date_s|
    @hire_date = Chronic.parse(hire_date_s)
end

When(^I schedule a review$/) do
    @review_scheduler.schedule(@hire_date)
end

Then(^the review should be scheduled for "(.*?)"$/) do |expected_review_date_s|
    expected_review_date = Chronic.parse(expected_review_date_s)
    Review.where("review_date = :review_date", {:review_date => expected_review_date}).exists?.should be true
end
#other steps


This is a maintainable solution which has the benefit of being in English. Lets say that instead of "90 days from now" your product owner changes his mind and decides that he want to schedule a review "60 days from today at noon". Chronic can handle the time aspect just as easily using the exact same step definition.

Here are some other examples of what Chronic can do (execute from irb):
1.8.7 :001 > require 'rubygems'
 => true 
1.8.7 :002 > require 'chronic'
 => true 
1.8.7 :003 > Chronic.parse('the second Tuesday July 2014')
 => Tue Jul 02 20:14:00 -0400 2013 
1.8.7 :004 > Chronic.parse('five months ago')
 => Thu Jan 17 21:41:29 -0500 2013 
1.8.7 :014 > Chronic.parse("one week from today at noon")
 => Mon Jun 24 12:00:00 -0400 2013
1.8.7 :015 > Chronic.parse("8 hours ago")
 => Mon Jun 17 14:00:02 -0400 2013 


These are just a few examples what Chronic is capable of, but as you can see it greatly increases your ability to write maintainable, user-friendly gherkin using the English language.

Saturday, June 8, 2013

Hello World From CMake!

I have recently been placed on a team which is developing an embedded application in C++.  To be honest I haven't touched C++ in years (as in not since college), and most of my career has been spent either in the JVM (predominantly Java and Groovy) or in the Ruby world.  Now I'm finding myself having to deal with things I've given scant thought to previously, such as pointers, destructors, operator implementations and other such nonsensical things that programmers as a whole shouldn't have to care about in this day and age.  In short I spent the last week getting my head handed to me and by a much more experienced developer (Who luckily is a great pair-partner who has been gracious and willing to share his knowledge with me.  Thank you Ben!), and so I decided it was time to bone up on my tech stack.

Aside from C++ I'm also picking up a new build tool; CMake.    CMake is certainly not a new tool, but this is the first time I've had to use it, and I thought I would share what I've learned about it so far.  As part of the learning process I have created a "Hello, World!" application using CMake, which I've made available at GitHub at https://github.com/jameskbride/cmake-hello-world .  This extremely simple application does exactly what you would expect, which is spitting out "Hello, world!" to command line, but it was a great opportunity to explore CMake.  So, lets get to it and dive into the CMake world!

Project Root CMakeLists.txt

CMake is primarily configured via 'CMakeLists.txt', which lives in the root of the project, as well as the root of every sub-project.  Lets take a look at the CMakeLists.txt file in the root of this project shall we?


cmake_minimum_required (VERSION 2.8)
project (CMakeHelloWorld)

#version number
set (CMakeHelloWorld_VERSION_MAJOR 1)
set (CMakeHelloWorld_VERSION_MINOR 0)

#include the subdirectory containing our libs
add_subdirectory (Hello)

#indicate the entry point for the executable
add_executable (CMakeHelloWorld Hello HelloWorld.cpp)

# Indicate which libraries to include during the link process.
target_link_libraries (CMakeHelloWorld Hello)

install (TARGETS CMakeHelloWorld DESTINATION bin)

As you can see this is a simple text file which contains CMake specific commands.  The first interesting bit here is line 2, which indicates the project name.:
project (CMakeHelloWorld)
Line 9 tells CMake where to find the header and .cpp files for the subproject.
add_subdirectory (Hello)

Line 12 indicates where the executable go resides, as well as the entry point for the application (HelloWorld.cpp).
add_executable (CMakeHelloWorld Hello HelloWorld.cpp)

I probably did not have to have the entry point in the root directory of the project, but I thought it would clearly separate it from the library code if I placed it there. Line 15 tells the linker which projects to use when wiring up the compiled units.
target_link_libraries (CMakeHelloWorld Hello)

Finally, line 17 tells CMake where to install the target project binaries.
install (TARGETS CMakeHelloWorld DESTINATION bin)

Subproject (Hello) CMakeLists.txt

In order to modularize the code I created a subdirectory which contains the Speaker.h and Speaker.cpp source files, which contain the logic for the class which actually produces the "Hello, World!" output. Here is the CMakeLists.txt file for that subproject:
add_library (Hello 
  Speaker.h
  Speaker.cpp)

install (TARGETS Hello DESTINATION bin)
install (FILES Speaker.h DESTINATION include)
Again, this is pretty straightforward. First we declare we are adding a library, "Hello", followed by a listing of the .h and .cpp files to be included as part of the build. We then define an install target for the subproject (Note: this does *not* create a new executable binary as part of the build.). Finally we define the list of header files to be included during the build.

Building the Project

During my first attempt to use CMake followed the instructions I found in various blogs which stated that I should simply go to the root of the project and execute
cmake . && make && make install
While this does build the project it has the undesirable effect of splattering build gore all over the walls of your project. Your directories will be littered with generated directories and files which you otherwise wouldn't care about. Luckily, the solution is simple. CMake allows you to point to where your CMakeLists.txt files live (the "cmake ." piece of the previous command). As such, creating a build directory, changing to it and executing
cmake  && make && make install
will execute the build and cause the resulting output to be dumped into your cleanly encapsulated build directory.

The build will now generate an executable file, CMakeHelloWorld, which can be called using the standard "./CMakeHelloWorld" command.

You now know as much as I currently know about CMake, so go forth and make! There will be more of these types of posts in the future, so I hope you found this informative and I hope you'll come back. For more detail be sure to check out the GitHub repo, and please feel free to leave feedback. Thanks!