Posts Tagged ‘storevil

23
Feb
10

StorEvil: What’s in a Name?

My Alt.NET Seattle compatriot Brian Henderson asked about the reason behind the name “StorEvil”.

It’s sort of a pun… first off, obviously, in agile development, a unit of work to-be-done is often referred to as “story”. In StorEvil, “Story” refers to a set of scenarios (basically a single natural language specification file).

Also, many years ago, when I was young and just getting into jazz, I listened to a certain live Charlie Parker album quite a bit.

Also, I’ve always had the suspicion that the whole idea of natural language specs might be slightly Evil.

So, being an old DOS/Windows guy, I just took “Storyville” and twisted it into an 8-character name that almost makes sense.

So there you have it, the triple-entendre behind the StorEvil name.

23
Feb
10

Introduction to StorEvil

StorEvil

This is the first in a series of posts about a tool I wrote a while back, and have recently picked up again, called StorEvil.

You can check out StorEvil on GitHub

After I wrote it I sort of lost interest in this whole approach, although I paid some attention to Cucumber as it gained popularity.
Recently, at an Alt.NET Seattle meeting, I saw a demo of SpecFlow, which is a similar tool for .NET.

SpecFlow is a nice tool insofar as it is basically a reimplementation of Cucumber in .NET.
However, I think that some of the nice metadata tools (Reflection) that we have in .NET can provide for a much richer experience.
This is not to imply that I think .NET is better than Ruby for this type of thing, by any means. In fact, quite the opposite.

But, if you are going to take on the pain of static-typing, I think you should partake of the joy of System.Reflection to provide a tool that does things that are simply not possible or very difficult in Ruby.
Otherwise, you might as well just use Cucumber and IronRuby… Or eschew .NET altogether if possible.

Now, big disclaimer: StorEvil is not very polished. It may not work on your machine. It may not work as expected.
I’m pretty sure that it won’t reformat your hard disk, but beyond that I make no claims.

What is StorEvil?

Well, if you know what Cucumber is, you can basically think of it as a Cucumber-ish tool for .NET that allows you to easily write .NET code to interpret natural language specifications.
If you don’t know what Cucumber is, I would advise you to read about it.

StorEvil is a tool that you can use to write specifications in English, and then execute those specifications.
It supports a set of natural language that is a subset of the Gherkin language used by Cucumber.

It supports .NET languages such as C#.
It has only been tested on Windows (so far).
It only supports English (so far).

Why StorEvil?

Reflection-based language matching

Other similar tools use regular expressions, which makes sense for Ruby.

In .NET, there is a rich Reflection model which gives access to the method names, parameter names and type info,
which can help to reduce noise and code-duplication.

In StorEvil, although Regular-Expression matching is supported, matching based on the names of functions is the preferred method:

For example, in order to match the following:

Given I have a savings account with $100
  

In SpecFlow, and similarly in Cucumber (ignoring the language differences between C# & Ruby), you would write something like this:

[Given(@"I have a (\w+) account with $(.*)")]
public void GivenIHaveAccount(string type, decimal amount) { ... }
  

In StorEvil, you could use similar syntax to the above, OR, you can write it in as follows:

public void Given_I_Have_A_accountType_Account_with_amount(string accountType, decimal amount) { ... }
  

StorEvil splits the method name into its constituent words and matches the values to the parameters based on the names of the parameters (accountType and amount).

Context Chaining

In StorEvil, your Context class methods (like Steps in Cucumber) can return any object, which can then be used to fulfill the remaining grammar on a line.

For example, in the specification alluded to in the above example, you may end up with the following similar steps:

Given I have a savings account with a balance of $100
Given I have a savings account that is preferred
Given I have a checking account that has been placed on fraud alert
  

In StorEvil, rather than creating a separate step for each one of these, you could do the following:

[StorEvil.Context]
public class AccountTestContext {
    public AccountOptions Given_I_Have_A_accountType_Account(string accountType) { 
        // create and return AccountOptions object here     
    }
}

public class AccountOptions {
    public void With_a_balance_of_accountBalance(decimal accountBalance) { ... }
    public void That_is_preferred() { ... }
    public void That_has_been_placed_on_fraud_alert() { ... }
}
  

StorEvil will first invoke AccountTestContext.GivenIHaveAaccountType_Account(), passing in the account type.
It will then take the returned AccountOptions object and invoke the appropriate method to complete the rest of the step.

You could also declare a method to return object or any other type, and return different types of objects from the function depending on the parameters.

This can be chained to as deep a level as desired.

On successive steps during a scenario, StorEvil will preserve the same context objects…
meaning that you can use private variables in the context objects to maintain state between steps.

Extension Method Support

StorEvil can invoke extension methods. For example, to interpret the following:

My total balance should equal $42
  

You could write something like this:

public static class TestExtensionMethods
{
    public static void ShouldEqual(this object actual, object expected)
    {
       ... assertion code here ...
    }
}

[StorEvil.Context]
public class AccountTestContext {
    ...

    public decimal My_Total_Balance { get { return ... ;}} 
}
  

StorEvil will invoke the .ShouldEqual() extension method on the number returned by AccountTestContext.MyTotalBalance property, passing in “$42”;

Executes in the console

StorEvil is executed via a simple command-line interface. This is my personal preference. It might not be for you if you are not comfortable on the command-line. Integration with ReSharper is something I’ve looked into but frankly, it’s kind of a bear and not high on the priority list right now.

It was originally written to generate NUnit fixtures (and still supports this), although there are some limitations to the NUnit fixture generation.

Why not StorEvil?

Less polished than other options

StorEvil does not have VisualStudio integration.

StorEvil does not have NAnt or MSBuild tasks. (yet)

It does not have TDD.NET or Resharper integration.
(Unless you use it in NUnit generation mode)

Update: I have built an alpha ReSharper runner (5.0 only)

Overall, it just a less-used tool than the other options.

Is natural language testing appropriate?

There is definitely an extra cost to writing natural language specs as well as context classes.
Sometimes it can even feels like “writing the tests twice”.

Another option is to use a tool whose output is close to the natural language specification.
For .NET development, Machine.Specifications (MSpec) is a good choice.

Other similar tools

Cucumber

Cucumber is by far the most established BDD tool, and if you use Ruby you have probably heard of it.
It is in use by a large number of people, supports many languages, and is under very active development.

SpecFlow

SpecFlow is another .NET tool that is similar to Cucumber. It also has a fairly active community.