📜 ⬆️ ⬇️

BDD practice example when working with Specter Framework

specter-log Specter is the infrastructure for composing object-behavioral specifications for .NET. It provides opportunities to ensure development, guided by system behavior ( BDD ), requiring developers to write an executable specification for objects before writing the objects themselves. Technically, this is no different from the development of test 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 . Read more about the environments here ).
Specter uses the meta-programming language of Boo (CLR .NET) to write well-readable specifications.

BDD practice example when working with Specter


For our example, consider the Bender mini-bar specification, 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 the readability of this code by third-party people from programming.
What did we write?
Everything is very simple, we created the NUnit TextFixture Class, which we are used to, and described the Test methods. Now I will tell 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 you go with a reflector into the assembly that we receive 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:
[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 .


Compliant:
[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 finished, then we need to write the code of our application, since The specter swore that the specification was not implemented:
minibar-result1[1]
Well, we realize our mini-bar:
namespace Bender
class MiniBar:
pass
* This source code was highlighted with Source Code Highlighter .


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


Nevertheless, the specter is not satisfied, since our method does not implement the work with the balance described in the specification:
minibar-result2[1]
We'll 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 .


I think the specter liked everything:
minibar-result3[1]
Great, so we practiced BDD.
So, we get the unit tests we are used to, but the motivation for writing is to change a little, and we will also get the opportunity to provide a specter-specification of tests as documentation. I think this is a great idea!

Resources


About BDD you can read 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)
Introduction to Behavior Driven Development (BDD) (rus.)
Download Specter here:
http://specter.sourceforge.net/

Source: https://habr.com/ru/post/60767/


All Articles