Insights and outlooks on software development

S'true

On using BDD methodologies in xUnit

Tuesday, October 2, 2007 by Thomas L

Say you're a developer in a shop not accepting that the co-workers install whichever tools they wish. Also say that you have eaten the BDD pill. How do you go about to make sure you are writing the best NUnit tests there is?

Well, one thing to notice is that the BDD toolset maps well to the existing xNUnit toolset. Where you have contexts in a BDD toolset it's possible to have test fixtures with setup methods making contexts in NUnit. Where you have a Test in xUnit, you have behaviours in BDD tools. This makes it possible to apply patterns for xUnit tests which somewhat satisfies the patterns in behaviour driven development. Let me show with an example.

Suppose we are writing a guestbook type of application, in a DDD fashion with the model object of Message, which is stored in the MessageRepository. We want to make sure that when the repository has messages, it's possible to find this message by its ID, but supplying an ID not in the repository should return null.

In NBehave, the BDD implementation should be somewhat like this

[TestFixture] public class BDD_FindMessageBehaviours { [Test] public void Searching_in_message_repository() { MessageRepository repository = null; Message message = null; Story searchingStory = new Story( "Searching in message repository" ); searchingStory .AsA( "Message poster" ) .IWant( "to add messages to the repository" ) .SoThat( "I later can retrieve them" ); searchingStory .WithScenario( "Having the message in the message repository" ) .Given( "an empty MessageRepository", delegate() { repository = new MessageRepository(); } ) .When( "I add message with Id", 1, delegate( int id ) { repository.Add( message = new Message( id ) ); } ) .Then( "The message should be in teh repository", 1, delegate( int id ) { Assert.AreSame( message, repository.FindById( id ) ); } ); searchingStory .WithScenario( "Not having the message in the message repository" ) .Given( "an empty MessageRepository", delegate() { repository = new MessageRepository(); } ) .When( "I add message with Id", 1, delegate( int id ) { repository.Add( message = new Message( id ) ); } ) .Then( "Searching for another message id should be impossible", -100, delegate(int id) { Assert.IsNull( repository.FindById( -100 ) ); } ); } }

In a xUnit implementation, I propose the following code

namespace OnUsingBddInXUnit.Behaviours.MessageRepositoryBehaviour { [TestFixture] public class HavingOneMessageInTheRepository { private MessageRepository _messageRepository; private Message _message; [SetUp] public void SetUp() { _messageRepository = new MessageRepository(); _message = new Message(); _message.Id = 1; //add other properties _messageRepository.Add( _message ); } [Test] public void SearchingForCorrectIdShouldReturnCorrectMessage() { Message foundMessage = _messageRepository.FindById( _message.Id ); Assert.AreSame( _message, foundMessage ); } [Test] public void SearchingForIncorrectIdShouldntReturnAnything() { Message shouldBeNull = _messageRepository.FindById( -100 ); Assert.IsNull( shouldBeNull ); } } }

In this short example I showed how it's possible to implement good NUnit-only code in a BDD-ish fashion. I hope some of you got new ideas on how to write those tests, which of course aren't tests, but specifications on behaviours.

Technorati-taggar: , ,

Filed under having  

0 kommentarer: