Phillip Trelford's Array

POKE 36879,255

DDD Belfast 2011

This weekend I flew into Belfast for their Developer Developer Developer (DDD)  conference. The DDD conferences are run by the developer community for the developer community, where sessions are voted on prior to the conference. I highly recommend these free events, there always seems to be a great range of interesting talks, not to mention plenty of lively discussion between sessions. The next event is DDD North next weekend, Saturday 8th October, in Sunderland.

Interestingly there were enough F# sessions at DDD Belfast to have a dedicated track (3), which is where I spent most of the day.

My first talk of the morning was F# Eye 4 the C# Guy (a title I ahem, recycled, from an excellent talk by Leon Bambrick given 3 years ago):

Next up was Tomas Petricek on Asynchronous Programming in F# and C#. If you’re in London, Tomas is repeating this talk at Skills Matter this Wednesday (5th October), register free here: http://www.meetup.com/fsharpLondon/

Shipping in VS11, C# 5’s Async (await) support will be very similar in implementation to C# 2’s Iterators (yield). They are both basically implementations of coroutines.

F#’s Async Workflows are available now in VS2010.

Before lunch I was up again to talk about Behavioural Driven Development (BDD) with F#:

After lunch Adam Granicz presented Developing F# Applications with WebSharper on track 3. I popped over to see Richard Dalton’s great information packed session Aha! Unit Testing.

Slides and samples: http://www.devjoy.com/2011/10/aha-unit-tests-dddbelfast/

Richard gave some really interesting observations, for example unit tests are “An Extra Client” (slide 5), and therefore it is OK to add artefacts in your code to support them. The talk presented a number of Aha! moments:

Unit Testing - Excutes Unit Testing - Real Reason

 

There were also some good tips on Mocks and Stubs (Stubs are Stooges, Mocks are Spies), including some code examples using TypeMock and references to Microsoft Research’s Moles project and Martin Fowler’s Mocks Aren’t Stubs article.

Track 3 ended with a lively Panel Discussion, which covered a variety of subjects from BDD, Concurrent programming with Agents, Parsers, Units of Measure through to games development.

Thanks again to all the attendees, sponsors, speakers and particularly Jackie Pollock for organizing the event.

What makes a good step definition

Following on from last week’s What makes a good feature file article, this week it’s time to tackle what makes a good step definition. To automatically test that an application’s behaviour matches that defined by the scenarios in a feature file, a mapping is required. Step definitions provide that mapping from the lines in a feature file to the code that implements the feature.

Starting with a Given:

Given I have entered 0.1134 into the calculator

Implementations

Ruby step definition for use with Cucumber::

Given /I have entered (.*) into the calculator/ do |n|
  # Some Ruby code here
end

The code above specifies a regular expression used to match lines in the feature file and an anonymous function to execute.

C# attributed step definition compatible with both SpecFlow and TickSpec:

[Given(@"I have entered (.*) into the calculator")]
public void GivenIHaveEnteredNIntoTheCalculator(int n)
{
  // C# code here
}

Again a regular expression is specified, however this time the function is public and reflection is used for invocation.

F# attributed step definition compatible with TickSpec:

let [<Given>] ``I have entered (.*) into the calculator``(n:int) =
  // F# code here
}

F# allows white space and special charecters in method names enclosed with backticks. This removes the need for both an attribute and a function name.

TickSpec also supports anonymous functions as Ruby with Cucumber, i.e.:

Given "I have entered (.*) into the calculator" (fun [Int n] –>
  // F# code here
)

From a terseness point of view it looks like Ruby and F# the advantage for writing step definitions. But that’s only part of the story…

Scope 

By default in frameworks like Cucumber and SpecFlow step definitions are defined globally, so that they can be shared or reused. Global functions are usually fine for small programs, but for larger programs we usually group them into classes or modules for maintainability.

With SpecFlow and TickSpec it is possible to constrain the scope of a step definition or set of step definitions via a StepScope attribute:

[StepScope(Feature="Addition")]
public class AdditionSteps
{
  [Given(@"I have entered (.*) into the calculator")]
  public void GivenIHaveEnteredNIntoTheCalculator(int n)
  {
    // C# code here
  }
}

Here the step definition methods in the AdditionSteps class are only matched against the Addition feature. This allows the wording in the feature file to evolve without affecting other feature files, and it allows the actions in the methods to vary too. It also means that it is easy to find the step definitions that map to a feature file in one place.

Using a class level step definition scope is quite similar conceptually to using a View Model within the MVVM pattern, where the View Model is responsible for mapping from view to model. It adds a layer of indirection over binding directly to the model, but allows the application to evolve more easily over time.

Note: TickSpec can apply scope to both Step bindings and Event bindings like BeforeScenario and AfterScenario. There is currently was an open bug on this in SpecFlow (since fixed).

Fluent interfaces

So far the step definition examples have included a “code here” comment. This is where we arrange, act and assert. In the Given steps the preconditions are arranged. The When steps execute the actions. Finally the Then steps assert the outcome. This is almost identical to the steps you’d take in TDD for a unit test, except the parts are spread across multiple methods.

Note: The state for a scenario can also be initialized in a method marked with BeforeScenario attribute

For the arrange and act steps, DSL approaches like fluent interfaces can be useful for making step definitions more readable and maintainable.

In the arrange steps using the builder pattern is useful to build up the initial state:

public void constructPizza()
{
  pizzaBuilder.createNewPizzaProduct();
  pizzaBuilder.buildDough();
  pizzaBuilder.buildSauce();
  pizzaBuilder.buildTopping();
}

In the act steps a fluent assertion API is useful, for example the FsUnit F# library:

1 |> should equal 1
anArray |> should haveLength 4
anObj |> should not (be Null)

Summary

Using fluent interfaces inside the step definition functions can make them more readable and maintainable. For larger projects constraining the scope of step definitions helps make them more maintainable. Finally step definitions can sometimes be written more concisely in languages like Ruby and F#.

What makes a good feature file

Back in March, Gojko Adzic and David De Florinier ran an illuminating interactive session at the excellent Cukeup! conference entitled What makes a good feature file. A feature file is a file containing a set of scenarios specified in Gherkin for consumption by Cucumber or a derivative thereof. No really ;)

Gherkin

Gojko’s opening statement rang true for me:

People focus on the automation part of Cucumber initially. Then they write 100s and 100s of feature files, which usually aren’t as useful as they could be

Clearly writing good feature files is important. However writing good feature files, as any good documentation, takes time, effort and collaboration.

Here’s Gojko & David’s tips for what makes a good feature file taken from the slides:

  • About the business domain – not software design
  • In domain language
  • Specification – not a script
  • Easy to understand
  • Focused on a single thing
  • Precise and testable
  • Self-explanatory
  • Consistent
  • Easy to access

There’s a great section in The Secret Ninja Cumber Scrolls also titled:

 What makes a good feature file

Our story needn't end there though…


Feature file style

Smells Like Teen Spirit

With the content for a good feature file explained, it’s time to turn our attention to style.

Sometimes it’s easier to say what we don’t like than what we do. So in a similar fashion to Martin Fowler’s Refactoring book let’s categorize some feature file bad smells and then define ways to neutralize the odour.

Categories of bad smell in a feature file:

  • Long sentences
  • Repetitious sentences
  • Repetitive scenarios
  • A Never ending story
  • Commentary
  • And another thing


Long sentences

Doing time

Diagnosis: There’s no easier way to lose a reader’s attention than overtly verbose sentences. If you find yourself having to use horizontal scroll to read a line then it’s probably too long.

Treatments:



Repetitious sentences

Lines

Diagnosis: The words in consecutive sentences somehow line up and few words vary between them. Nothing works better for putting the reader to sleep.

Treatments:

  • Extract the parts that vary into a table


Repetitive scenarios

Repetition

Diagnosis: The sentences in consecutive scenarios look almost identical, bar a few words varying between them. Nothing works better for confusing the reader.

Treatments:



A Never ending story

Neverending story

Diagnosis: Just like the 80s film of the same name, the story goes on and on, until the reader’s eyes start to glaze over. As a rule of thumb if a paragraph is longer than say 7 sentences, then it’s too long, the same can be applied for scenarios.

Treatment:

  • Consider using a background
  • Break up the scenario
  • Break the scenario up with tables


Commentary

8-2

Diagnosis: The scenario is so hard to follow that it has been commented. Yes, the document needs documentation. Documentation is not code.

Treatment:

  • Start again


And Another Thing 

And another thing

Diagnosis: Just when you thought you’d reached the end… Given proceeds When which proceeds Then, but wait there’s another thing, another Given.

Treatments:

  • Try describing the initial state in a single line.
  • Split into multiple scenarios


Positive Example

How does a good feature file look then? Here’s an example from Gojko & David’s slides:


Feature: Free Delivery 
In order to increase customer loyalty VIP customers buying a lot of books should get free delivery 

Scenario outline: Free delivery 
Given the threshold for free delivery is 10 books 
And the customer is <type> with <books> in the cart 
When checking out 
Then free delivery is <free delivery> 

Examples 
| type   | books | free delivery | 
| VIP    |   9   | not offered   | 
| VIP    |  10   | offered       | 
| VIP    |  11   | offered       | 
| Normal |  10   | not offered   |



Collaboration

Drawing Collaboration

In Liz Keogh’s words from the article Step Away from the Tools:

Start by having conversations, engaging both testers and business stakeholders

If you can’t have those conversations, stop. You can’t do BDD



Summary

Feature files are documents, and good documents should be short and to the point, easy to read and not put the reader to sleep. The real secret to good documentation is collaboration and review.

Has anyone read your feature file? Try inserting a particularly fallacious or comical statement towards the end and see if anyone mentions it ;)

Do you have some bad smells to share?



Further reading