08 June 2013

Specs2 2.0 - Interpolated - RC2

This is a quick update to present the main differences with specs2 2.0-RC1. I have been fixing a few bugs but more importantly I have:

  • made the Tags trait part of the standard specification
  • removed some arguments for reporting and made the formatting of specifications more granular

This all started with an issue on Github...


Creating reports for specifications is a bit tricky. On one hand you hand different possible "styles" for the specifications: "old" acceptance style (with the ^ operator), "new" acceptance style (with interpolated strings), "unit" style... Then, on the other hand, you want to report the results in the console, where information is logged on a line-by-line base and in HTML files, where newlines, whitespace and indentation all needs great care.

I don't think I got it quite right yet, especially for HTML, but working on issue #162 forced me to make specs2 implementation and API a bit more flexible. In particular, in specs2 < 2.0, you could set some arguments to control the display of the specification in the console and/or HTML. For example noindent is a Specification argument saying that you don't want the automatic indentation of text and examples. And markdown = false means that you don't want text to be parsed as Markdown before being rendered to HTML.

However issue 162 shows that setting formatting properties at the level of the whole specification doesn't play well with other features like specification inclusion. I decided to fix this issue by using an existing specs2 feature: tags.

Tags and Specification

Tags in specs2 are different from tags you can find in other testing libraries. Not only you can tag single examples but you can also mark a full section of a specification with some tags. We can use this capability to select specific parts of a specification for execution but we can also use it to direct the formatting of the specification text. For example you can now write:

class MySpec extends Specification { def is = s2""" ${formatSection(verbatim = false)}
 This text uses Markdown when printed to html, however if some text is indented with 4 spaces
     it should *not* be rendered as a code block because `verbatim` is false.


Given the versatile use of tags now, I decided to include the Tags trait, by default, in the Specification class. I resisted doing that in the past because I didn't want to encumber too much the Specification namespace with something that was rarely used by some users. Which leads me to the following tip on how to use the Specification class:

  • when starting a new project or prototyping some code, use the Specification class directly with all inherited features

  • when making your project more robust and production-like, create your own Spec trait, generally inheriting from the BaseSpecification class for basic features, and mix in only the traits you think you will generally use

This should give you more flexibility and choice over which specs2 feature you want to use with a minimal cost in terms of namespace footprint and compile times (because each new implicit you bring in might have an impact in terms of performances)

API changes

The consequence of this evolution is yet another API break:

  • the Text and Example classes now use a FormattedString class containing the necessary parameters to display that string as HTML or in the console
  • for implementation reasons I have actually changed the constructor parameters of all Fragment classes to avoid storing state as private variables
  • the noindent, markdown arguments are now gone (you need to replace them with ${formatSection(flow=true)} and ${formatSection(markdown=true)}, see below)
  • the Tags trait is mixed in the Specification class so if you had methods like def tag you might get conflicts

And there are now 2 methods formatSection(flow: Boolean, markdown: Boolean, verbatim: Boolean) and formatTag(flow: Boolean, markdown: Boolean, verbatim: Boolean) to tag specification fragments with the following parameters:

  • flow: the fragment (Text or Example) shouldn't be reported with automatic indenting (default = false, set automatically to true when using s2 interpolated strings)
  • markdown: the fragment is using Markdown (default = true)
  • verbatim: indented text with more than 4 spaces must be rendered as a code block (default = true but can be set to false to solve #162)

HTML reports

I'm currently thinking that I should try out a brand new way of translating an executed specification with interpolated text into HTML. My first attempts were not completely successful and I find it hard to preserve the original layout of the specification text, especially with the Markdown translation in the middle. Yet, I must say a word on the Markdown library I'm using, Pegdown. I found this library extremely easy to adapt for my current needs (to implement the verbatim = false option) and I send my kudos to Mathias for such a great job.

This is it. Download RC2, use it and provide feedback as usual, thanks!