I've been using a home brewed BDD Spec extension for writing BDD style tests in NUnit, and I wanted to see what everyone thought. Does it add value? Does is suck? If so why? Is there something better out there?
Here's the source: https://github.com/mjezzi/NSpec
There are two reasons I created this
Here's an example of how a test will look:
-since zombies seem to be popular these days..
Given a Zombie, Peson, and IWeapon:
namespace Project.Tests.PersonVsZombie
{
public class Zombie
{
}
public interface IWeapon
{
void UseAgainst( Zombie zombie );
}
public class Person
{
private IWeapon _weapon;
public bool IsStillAlive { get; set; }
public Person( IWeapon weapon )
{
IsStillAlive = true;
_weapon = weapon;
}
public void Attack( Zombie zombie )
{
if( _weapon != null )
_weapon.UseAgainst( zombie );
else
IsStillAlive = false;
}
}
}
And the NSpec styled tests:
public class PersonAttacksZombieTests
{
[Test]
public void When_a_person_with_a_weapon_attacks_a_zombie()
{
var zombie = new Zombie();
var weaponMock = new Mock<IWeapon>();
var person = new Person( weaponMock.Object );
person.Attack( zombie );
"It should use the weapon against the zombie".ProveBy( spec =>
weaponMock.Verify( x => x.UseAgainst( zombie ), spec ) );
"It should keep the person alive".ProveBy( spec =>
Assert.That( person.IsStillAlive, Is.True, spec ) );
}
[Test]
public void When_a_person_without_a_weapon_attacks_a_zombie()
{
var zombie = new Zombie();
var person = new Person( null );
person.Attack( zombie );
"It should cause the person to die".ProveBy( spec =>
Assert.That( person.IsStillAlive, Is.False, spec ) );
}
}
You'll get the Spec output in the output window:
[PersonVsZombie]
- PersonAttacksZombieTests
When a person with a weapon attacks a zombie
It should use the weapon against the zombie
It should keep the person alive
When a person without a weapon attacks a zombie
It should cause the person to die
2 passed, 0 failed, 0 skipped, took 0.39 seconds (NUnit 2.5.5).
Most BDD tests are written in a business-readable programming language called Gherkin, which describes business behavior without going into detail of how it is implemented. Those frameworks that do not use Gherkin use non-Gherkin domain-specific languages (DSLs) that have BDD-like features.
Here is an introductory guide on how to use Behaviour-Driven Development (BDD) with C# and SpecFlow in a . NET application. Photo by Taras Shypka on Unsplash. Behaviour-Driven Development (BDD) is a technique of agile software development to ensure that the requirements of the software to be developed are fulfilled.
Concordion. Concordion is one of the most powerful BDD testing tools for writing acceptance test automation scripts. It supports Java IDEs like Eclipse and Netbeans. Concordion also supports Excel, which allows you to write the specifications in the spreadsheets.
What is BDD (Behavior-Driven Development)? Behavior-driven development is a testing practice that follows the idea of specification by example (e.g., Test-Driven Development [TDD]). The idea is to describe how the application should behave in a very simple user/business-focused language.
I'm going to call out some uses of BDD rather than just the framework, as I think having a really great understanding of unit-level BDD might affect some of the things you create. Overall, I like it. Here goes:
Rather than calling them PersonAttacksZombieTests
, I'd just call them PersonTests
or even PersonBehaviour
. It makes it much easier to find the examples associated with a particular class this way, letting you use them as documentation.
It doesn't look like IsStillAlive
is the kind of thing you'd want to set on a person; rather an intrinsic property. Careful making things like this public. You're adding behaviour that you don't need.
Calling new Person(null)
doesn't seem particularly intuitive. If I wanted to create a person without a weapon, I would normally look for a constructor new Person()
. A good trick with BDD is to write the API you want, then make the code underneath do the hard work - make code easy to use, rather than easy to write.
The behaviour and responsibilities also seem a bit odd to me. Why is the person, and not the zombie, responsible for determining whether the person lives or dies? I'd prefer to see behaviour like this:
person.Equip(IWeapon weapon)
).person.Kill
).That seems to me as if it's got the behaviour and responsibilities in a better place. Using a different kind of weapon for useless attacks, rather than checking for null, also allows you to avoid that if
statement. You'd need different tests:
Other than that, it looks great. I like the way you've used the mocks, the flow of strings, and the phrasing of the test methods themselves. I also quite like ProveBy
; it's doing exactly what it says on the tin, and nicely ties up the difference between providing examples of behaviour and running them as tests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With