BDD Case Study for Specter Framework
Specter 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.
For our example, consider the specification of the Bender minibar, it will look like this:
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:
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:
Next, look at:
This is the usual SetUp for us:
The following line is interesting to us:
It is already a test:
Similarly, the following lines correspond:
The same tests:
And one more line:
Conforms to:
The specification is over, then we need to write the CODE of our application, because specter swore that the specification was not implemented:
Well, we are implementing our minibar:
And add the necessary method:
Nevertheless, specter is not satisfied, since our method does not implement the work with balance described in the specification:
We have to add an implementation:
In my opinion, the specter liked everything:
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!
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/
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:
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:
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:
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/