BDD with DSL: Aubergine, a ruby/cucumber like alternative for .NET - download available

Update

Again a lot has changed : look here

 

 

Introduction

In this article you can download the very first alpha version of Aubergine; a BDD /DSL framework for .Net, initially based on Machine.Specifications, but later on heavily inspired by Cucumber. It is AFAIK the very first Cucumber like environment in .NET available, and you will see that it is very easy to use. Due to it's inspirator (Cucumber, I have decided to use the name Aubergine - I have no idea if they are actually related or not Undecided .

Please do note that it is an alpha version, so right now we only have a single testrunner that outputs to the console (i.e. no unit test integration yet). In the article I do include a postbuild step, which automatically makes my BDD tests run after each build, and displays the output in notepad, which is fine for me atm.

Anyway, enough with the talkin, Let's Get Busy !!!

 

Getting Started

First you need to download the example project; it includes all the binaries needed to do your BDD development. You can find it here :

Be.Corebvba.Aubergine.Examples.zip (16,43 kb)

Once you have the zip file, you can either explore the project, or walk through the following scenario to create your own test.

  1. Create a new .Net project in visual studio/any ide you use
  2. Add a reference to Be.Corebvba.Aubergine.DLL (can be found in the zip under the "lib" folder

 

 

Creating a story

Add a class named "BrowserContext" to your project

Add a class named "Make_sure_my_website_gets_enough_visibility" , import the Be.Corebvba.Aubergine namespace, and derive your class from Story<BrowserContext>

Then you can start typeing your story; the final file should look like this :


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Be.Corebvba.Aubergine;

namespace Example
{
    class Make_sure_my_website_gets_enough_visibility: Story&lt;BrowserContext&gt;
    {
        As_a website_owner;
        I_want to_make_sure_that_I_get_enough_visibility;
        So_that I_can_get_enough_traffic;

        [Cols("searchengine","search_url","keywords","my_url")]
        [Data("google","https://www.google.be/search?q=","core bvba tom janssens","www.corebvba.be")]
        [Data("google","https://www.google.be/search?q=","BDD .Net","www.corebvba.be")]
        [Data("bing","https://www.bing.com/search?q=","core bvba tom janssens","www.corebvba.be")]
        class Search_results_for_keywords_on_searchengine_should_contain_my_url : Scenario
        {
            Given current_url_is_search_url;
            When searching_for_keywords;
            Then result_should_contain_my_url;
        }
    }  
}

 

Define the context class

After having created a story with scenarios we need to define the context for these scenarios.

You add all your domain objects that need to be tested to the "BrowserContext" class

In this case it is quite simple :


    public class BrowserContext
    {
        public string Url { get; set; }
        public string Result { get; set; }

        private WebClient wc = new WebClient();
    }
          

This should be enough to test, but wait, isn't there something missing ?

 

The context DSL

Next up we need to define how to interpret the story. As I allready mentioned; this is heavily inspired by Ruby/Cucumber : regular expressions are used to find out how all scenario steps should be matched to a real function. While this maybe sounds complicated, it really isn't; this is the code :


    public class BrowserContext
    {
        public string Url { get; set; }
        public string Result { get; set; }

        private WebClient wc = new WebClient();
           
        [DSL("current_url_is_(.*)")]
        void SetUrl(string url)
        {
            Url = url;
        }

        [DSL("searching_for_(.*)")]
        void SearchForKeyWords(string keywords)
        {
            Result = wc.DownloadString(Url + HttpUtility.UrlEncode(keywords));
        }

        [DSL("result_should_contain_(.*)")]
        void ResultShouldContain(string myurl)
        {
            Result.Contains(myurl).ShouldEqual(true);
        }

    }




That's all there is to it; you are ready to run your tests now !!!

 

Running the specs

Ok, since we do not want to run these tests manually each time, but at every build action, we need to add a postbuildstep.

In visual studio you can do it like this :

  1. Menu : Project/Properties
  2. Tab build events
  3. put the following text in the post-build-event commandline :

 

"$(ProjectDir)\lib\Be.Corebvba.Aubergine.ConsoleRunner.exe" "$(TargetPath)" > "$(TargetDir)output.txt"
"$(TargetDir)output.txt"
exit 0 

 

Now build your project, and the tests will be ran !! Your default texteditor will start, and it should contain this text :

==STORY================================================================
Make_sure_my_website_gets_enough_visibility => OK
========================================================================
   Search_results_for_core bvba tom janssens_on_google_should_contain_www.corebvba.be => OK
      Given current_url_is_https://www.google.be/search?q= => OK
      When searching_for_core bvba tom janssens => OK
      Then result_should_contain_www.corebvba.be => OK
   Search_results_for_core bvba tom janssens_on_bing_should_contain_www.corebvba.be => OK
      Given current_url_is_https://www.bing.com/search?q= => OK
      When searching_for_core bvba tom janssens => OK
      Then result_should_contain_www.corebvba.be => OK
   Search_results_for_BDD .Net_on_google_should_contain_www.corebvba.be => OK
      Given current_url_is_https://www.google.be/search?q= => OK
      When searching_for_BDD .Net => OK
      Then result_should_contain_www.corebvba.be => OK

 

So how does this work ?

It's actually quite easy once you have the hang of it; this is pseudocode :

 

   foreach (var story in AllClassesDerivedFromTheAubergineStoryClass) 
      foreach(var scenario in AllPossibleScenariosFor(story))
         create a new context object
         foreach (var possiblesteps in AllSteps (given,when,then) in story and scenario)
            find a regex DSL match for possiblesteps.name in the context, extract all the regex groups and add them as string parameters to the function you call
            call the corresponding step function

 

If one of this steps should fail then the test fails and the reason is mentioned in the report.

If you expect a step to fail, then you should add a membervariable named "&lt;steptype&gt;Exception", and if a step of that type fails, the step is marked as successfull, but the Exceptionvariable will contain the exception thrown. You can see an example of this in the Example zip file.

Bookmark and Share