BDD Case Study for Specter Framework

    specter-logSpecter is an infrastructure for compiling object-behavioral specifications for .NET. It provides opportunities for development, guided by the behavior of the system ( BDD ), requiring developers to write an executable specification for objects before writing the objects themselves. Technically, this is no different from the development of testing tools ( TDD ), although differences in the form of writing remove the psychological barrier to writing “tests” for code that does not yet exist. There are many projects for various platforms that implement this idea (For example, RSpec for Ruby , NSpec for .NET . More about environments here ).
    Specter uses the Boo meta-programming language (CLR .NET) to write well-read specifications.

    Spectrum BDD Case Study


    For our example, consider the specification of the Bender minibar, it will look like this:
    import Specter.Framework
    import Bender
    context "At Bender's bar":
       _bar as duck #our subject is defined in the setup block below
       setup:
         subject _bar = Bender.MiniBar()
       #one-liner shorthand
       specify { _bar.DrinkOneBeer() }.Must.Not.Throw()
       specify "If I drink 5 beers then I owe 5 bucks":
         for i in range(5):
           _bar.DrinkOneBeer()
         _bar.Balance.Must.Equal(-5)
       specify "If I drink more than ten beers then I get drunk":
         for i in range(10):
           _bar.DrinkOneBeer()
         { _bar.DrinkOneBeer() }.Must.Throw()
    * This source code was highlighted with Source Code Highlighter.


    I would like to separately note the possibility of readability of this code by third-party people from programming.
    What did we write?
    Everything is very simple, we created the familiar NUnit TextFixture Class and described Test methods. Now I’ll tell you how it happened. Pay attention to the following line:
    context "At Bender's bar":
    * This source code was highlighted with Source Code Highlighter.


    We define a certain context. What is he like? In fact, if we use the reflector in the assembly we get when compiling the specification, we find that this context is the TextFixture Class itself:
    [NUnit.Framework.TestFixture]
    class EmptyStack:
    * This source code was highlighted with Source Code Highlighter.


    Next, look at:
    setup:
      subject _bar = Bender.MiniBar()
    * This source code was highlighted with Source Code Highlighter.


    This is the usual SetUp for us:
    [NUnit.Framework.SetUp]
     public void SetUp()
    {
       subject _bar = Bender.MiniBar();
    }
    * This source code was highlighted with Source Code Highlighter.


    The following line is interesting to us:
    specify { _bar.DrinkOneBeer() }.Must.Not.Throw()
    * This source code was highlighted with Source Code Highlighter.


    It is already a test:
    [NUnit.Framework.Test]
    public void BarDrinkOneBeerMustNotThrow()
    {  
        Assert.DoesNotThrow(_bar.DrinkOneBeer());
    }
    * This source code was highlighted with Source Code Highlighter.


    Similarly, the following lines correspond:
    specify "If I drink 5 beers then I owe 5 bucks":  
    for i in range(5):
         _bar.DrinkOneBeer()
       _bar.Balance.Must.Equal(-5)
    * This source code was highlighted with Source Code Highlighter.


    The same tests:
    [NUnit.Framework.Test]
    public void IfIDrink5BeersThenIOwe5Bucks()
    {
       for (int i = 0; i == 5; i++)
         _bar.DrinkOneBeer();
       Int32MustModule.Must(_bar.Balance, “Bar balance must equal -5").Equal(-5);
    }
    * This source code was highlighted with Source Code Highlighter.


    And one more line:
    specify "If I drink more than ten beers then I get drunk":
       for i in range(10):
         _bar.DrinkOneBeer()
       { _bar.DrinkOneBeer() }.Must.Throw()
    * This source code was highlighted with Source Code Highlighter.


    Conforms to:
    [NUnit.Framework.Test]
     public void IfiDrinkMoreThanTenBeersThenIGetDrunk()
    {
       for (int i = 0; i == 10; i++)
       {
         _bar.DrinkOneBeer();
       }
       Assert.Throws((typeof(InvalidOperationException), _bar.DrinkOneBeer()); }
    * This source code was highlighted with Source Code Highlighter.



    The specification is over, then we need to write the CODE of our application, because specter swore that the specification was not implemented:
    minibar-result1 [1]
    Well, we are implementing our minibar:
    namespace Bender     
    class MiniBar:
       pass
    * This source code was highlighted with Source Code Highlighter.


    And add the necessary method:
    namespace Bender
    class MiniBar:
        def DrinkOneBeer():
            pass
        [getter(Balance)]
        _balance = 0
    * This source code was highlighted with Source Code Highlighter.


    Nevertheless, specter is not satisfied, since our method does not implement the work with balance described in the specification:
    minibar-result2 [1]
    We have to add an implementation:
    namespace Bender
    class MiniBar:
        def DrinkOneBeer():
            _balance--
    	if _balance <-10:
    		raise System.Exception ("i'm drunk")

        [getter(Balance)]
        _balance = 0
    * This source code was highlighted with Source Code Highlighter.


    In my opinion, the specter liked everything:
    minibar-result3 [1]
    Great, so we practiced BDD.
    So, we get unit tests that are familiar to us, however, the motivation for writing changes a bit, and we also acquire such an opportunity as providing the specter specification of tests as documentation. I think this is a great idea!

    Resources


    You can read about BDD here:
    http://habrahabr.ru/blogs/testing/52929/ (about BDD in Russian using RSpec as an example, there are links at the end of the article)
    Getting to know Behavior Driven Development (BDD) (Russian)
    You can download Specter here:
    http://specter.sourceforge.net/

    Also popular now: