OK, this just didn't seem worth it.

17 views
Skip to first unread message

David Starr

unread,
Apr 22, 2009, 1:42:54 AM4/22/09
to behaviordriv...@googlegroups.com, Jarod Ferguson
Attached is my first attempt at using a "BDD framework" instead of just using naming conventions. It was with StoryQ, but I don't know that there would be a huge difference with NBehave or MSpec. Syntax from what I can tell.

I have my language with the customer down. Seriously. The language translated into this model, however? umm....

And I really felt like I was forcing the heck out of this to make the narrative work. The framework guided me in places I would not have gone without it, and I don't think the places were all that great to visit.

For example, the framework apparently wants me to use multiple scenarios in a single [Test], which means basically I am sharing context. That just simply isn't going to work. So I jumped through some hoops to force it.

I must be missing something here, guys. Is there a fundamental way to organize these tests I am doing incorrectly? Inheritance of context doesn't feel right, either.

I ended up with 3 tests for the same story that produced the following sentences that I would never say aloud:

Story: cancel adding of a new recipe

  As a person entering a new recipe
  I want to to cancel the entry before I am done
  So that I can change my mind about entering the recipe

  Scenario 1: User confirms cancellation
    Given The user is entering a recipe                    Passed
      And The user wants to cancel                         Passed
    When The user cancels the entry                        Passed
    Then The view closes                                   Passed


Story: cancel adding of a new recipe

  As a person entering a new recipe
  I want to to cancel the entry before I am done
  So that I can change my mind about entering the recipe

  Scenario 1: User denies cancellation
    Given The user is entering a recipe                    Passed
      And There is data in the entry form                  Passed
      And The user doesnt really want to cancel            Passed
    When The user cancels the entry                        Passed
    Then The user is still editing the same data           Passed
      And The recipe is not saved                          Passed


Story: cancel adding of a new recipe

  As a person entering a new recipe
  I want to to cancel the entry before I am done
  So that I can change my mind about entering the recipe

  Scenario 1: User is prompted to confirm cancellation
    Given The user is entering a recipe                    Passed
    When The user cancels the entry                        Passed
    Then The user is presented with a confirmation         Passed
      And The recipe is not saved                          Passed

David Starr
elegantcode.com | pluralsight.com

Story_cancel_adding_a_new_recipe.cs

Jimmy Bogard

unread,
Apr 22, 2009, 8:21:43 AM4/22/09
to behaviordriv...@googlegroups.com
NBehave story runner, no. MSpec, yes. MSpec is context/specification style.  Honestly, just naming conventions in namespace, test class and test method names goes a long way.  I'd suggest experimenting with those before moving on to choosing a framework.

Scenarios written in a static language such as C# is hard.  I don't think any current framework right now does it especially well.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using RecipeBox.Persistence;
using RecipeBox.Presenters;
using RecipeBox.Views;
using StoryQ.Framework;

namespace RecipeBoxClientSpecs.UserStories.EnteringARecipe
{
   [TestClass]
   public class Story_cancel_adding_a_new_recipe
   {
       private Story _story;

       private EntryScreenPresenter _presenter;
       private Mock<IRecipeRepository> _recipeRepo;
       private Mock<IRecipeEntryScreenView> _view;

       [TestInitialize]
       public void StoryInit()
       {
           _story = new Story("cancel adding of a new recipe");
           _story.AsA("person entering a new recipe")
               .IWant("to to cancel the entry before I am done")
               .SoThat("I can change my mind about entering the recipe");
       }

       [TestMethod]
       public void user_is_prompted_to_confirm_cancellation()
       {
           _story.WithScenario("User is prompted to confirm cancellation")
               .Given(() => TheUserIsEnteringARecipe())
               .When(() => TheUserCancelsTheEntry())
               .Then(() => TheUserIsPresentedWithAConfirmation())
                   .And(() => TheRecipeIsNotSaved());
           _story.Assert();
       }

       [TestMethod]
       public void user_denies_cancellation()
       {
           _story.WithScenario("User denies cancellation")
               .Given(() => TheUserIsEnteringARecipe())
                   .And(() => ThereIsDataInTheEntryForm())
                   .And(() => TheUserDoesntReallyWantToCancel())
               .When(() => TheUserCancelsTheEntry())
               .Then(() => TheUserIsStillEditingTheSameData())
                   .And(() => TheRecipeIsNotSaved());

           _story.Assert();
       }

       private void TheRecipeIsNotSaved()
       {
           _recipeRepo.Verify(x => x.Save(null), Times.Never());
       }

       [TestMethod]
       public void user_confirms_cancellation()
       {
           _story.WithScenario("User confirms cancellation")
               .Given(() => TheUserIsEnteringARecipe())
                   .And(() => TheUserWantsToCancel())
               .When(() => TheUserCancelsTheEntry())
               .Then(() => TheViewCloses());

           _story.Assert();
       }

       private void TheViewCloses()
       {
           _view.Verify(x => x.Close());
       }

       private void TheUserIsStillEditingTheSameData()
       {
           Assert.IsFalse(string.IsNullOrEmpty(_view.Object.Title));
           Assert.IsFalse(string.IsNullOrEmpty(_view.Object.Notes));
       }

       private void ThereIsDataInTheEntryForm()
       {
           _view.SetupProperty(x => x.Title, "Title");
           _view.SetupProperty(x => x.Notes, "Notes");
       }

       private void TheUserIsPresentedWithAConfirmation()
       {
           _view.Verify(x => x.ConfirmAction());
       }

       private void TheUserCancelsTheEntry()
       {
           _presenter.CancelEntry();
       }

       private void TheUserIsEnteringARecipe()
       {
           _view = new Mock<IRecipeEntryScreenView>();
           _view.SetupAllProperties();

           _recipeRepo = new Mock<IRecipeRepository>();
           _presenter = new EntryScreenPresenter(_view.Object, _recipeRepo.Object);
       }

       private void TheUserDoesntReallyWantToCancel()
       {
           _view.Setup(x => x.ConfirmAction()).Returns(false);
       }

       private void TheUserWantsToCancel()
       {
           _view.Setup(x => x.ConfirmAction()).Returns(true);
       }
   }
}

Derick Bailey

unread,
Apr 22, 2009, 10:07:23 AM4/22/09
to behaviordriv...@googlegroups.com
I think that most C# BDD frameworks are detrimental the learning of BDD. don't bother with a framework, other than what you would normally use for your unit tests... nunit, xunit, mbunit, or whatever you normally use. learn to shape the language that you want to see, from a behavioral perspective with a simple unit testing framework, first. once you have the language that you want, in your tests, then find a framework that fits your language needs.

personally, i'm fond of SpecUnit.NET. I know everyone says to use MSpec instead (include Scott Bellware, who wrote SpecUnit), but i don't like MSpec. the stupid crotch-operator static syntax is annoying to me, and gets in the way of writing and more importantly, reading, my tests. SpecUnit is nothing more than a facade on top of nunit, giving us a base class to start with and help shape the language of the tests. where SpecUnit fails, i pick up with NUnit's built in functionality.

but remember... language first, framework second.

  -derick.

____________
"END OF LINE"
derickbailey.com
derickbailey.lostechies.com
Follow Me: @derickbailey



From: "Jimmy Bogard" <jimmy....@gmail.com>
Sent: Wednesday, April 22, 2009 7:22 AM
To: behaviordriv...@googlegroups.com
Subject: [BehaviourDrivenDevelopment] Re: OK, this just didn't seem worth it.

Raymond Lewallen

unread,
Apr 22, 2009, 10:12:34 AM4/22/09
to behaviordriv...@googlegroups.com
Derick, regarding SpecUnit vs MSpec.  The crotch operator is not english language, thus becomes an instant passover for your eyes when reading specifications.  SpecUnit still has words like public void and the like, which are english language words which catch your eyes.  You have to see them then throw them away.  By removing english language that has nothing to do with the specification, I think this is where MSpec wins the battle.

Derick Bailey

unread,
Apr 22, 2009, 10:21:43 AM4/22/09
to behaviordriv...@googlegroups.com
good points, Raymond. though i'm still not yet convinced that mspec is the winner. :) i guess it comes down to what you're used to seeing and what you've trained your brain to ignore. I'll have to give mspec another try sometime soon, and see what i think of it after i get passed training my eyes / brain.


  -derick.

____________
"END OF LINE"
derickbailey.com
derickbailey.lostechies.com
Follow Me: @derickbailey



From: "Raymond Lewallen" <rlew...@gmail.com>
Sent: Wednesday, April 22, 2009 9:13 AM

David Starr

unread,
Apr 22, 2009, 11:44:13 AM4/22/09
to Behaviour Driven Development
I have been doing BDD naming on classes, tests, etc. for awhile now. I
was really after the next level here.

One constraint is that I need to run in MSTest. I just do, that's
why. :)

I think I am on board for foregoing this tooling for the time being. I
had to spend a day looking into it just to see what would turn out.
Now I know.

Somewhere the holy grail of executable specification is churning. I
just want to be there for it.
> > }- Hide quoted text -
>
> - Show quoted text -

Derick Bailey

unread,
Apr 22, 2009, 11:47:24 AM4/22/09
to behaviordriv...@googlegroups.com
"Somewhere the holy grail of executable specification is churning. I
just want to be there for it."

you better start learning Ruby. :)



____________
"END OF LINE"
derickbailey.com
derickbailey.lostechies.com
Follow Me: @derickbailey



From: "David Starr" <da...@elegantcode.com>
Sent: Wednesday, April 22, 2009 10:45 AM
To: "Behaviour Driven Development" <behaviordriv...@googlegroups.com>

Subject: [BehaviourDrivenDevelopment] Re: OK, this just didn't seem worth it.
> >        private Mock _recipeRepo;
> >        private Mock _view;
> >            _view = new Mock();
> >            _view.SetupAllProperties();
>
> >            _recipeRepo = new Mock();
Reply all
Reply to author
Forward
0 new messages