Behave# enables Behavior Driven Testing, raises some interesting questions

Update: More on BDD and Behave# from AgileJoe here.

AgileJoe pinged me with an email about Behave#, a Behavior-Driven-Development verification API (think NUnit syntax with a more real-world feel of behavior descriptions). Here's what a "test" might look like using this API:

   1:  [Test]
   2:  public void Transfer_to_cash_account()
   3:  {
   4:   
   5:      Account savings = null;
   6:      Account cash = null;
   7:   
   8:      Story transferStory = new Story("Transfer to cash account");
   9:   
  10:      transferStory
  11:          .AsA("savings account holder")
  12:          .IWant("to transfer money from my savings account")
  13:          .SoThat("I can get cash easily from an ATM");
  14:   
  15:      transferStory
  16:          .WithScenario("Savings account is in credit")
  17:   
  18:              .Given("my savings account balance is", 100, delegate(int accountBalance) { savings = new Account(accountBalance); })
  19:                  .And("my cash account balance is", 10, delegate(int accountBalance) { cash = new Account(accountBalance); })
  20:              .When("I transfer to cash account", 20, delegate(int transferAmount) { savings.TransferTo(cash, transferAmount); })
  21:              .Then("my savings account balance should be", 80, delegate(int expectedBalance) { Assert.AreEqual(expectedBalance, savings.Balance); })
  22:                  .And("my cash account balance should be", 30, delegate(int expectedBalance) { Assert.AreEqual(expectedBalance, cash.Balance); })
  23:   
  24:        //Reuse the declarations and associated actions from before
  25:              .Given("my savings account balance is", 400)
  26:                  .And("my cash account balance is", 100)
  27:              .When("I transfer to cash account", 100)
  28:              .Then("my savings account balance should be", 300)
  29:                  .And("my cash account balance should be", 200)
  30:   
  31:      transferStory
  32:          .WithScenario("Savings account is overdrawn")
  33:   
  34:              .Given("my savings account balance is", -20)
  35:                  .And("my cash account balance is", 10)
  36:              .When("I transfer to cash account", 20)
  37:              .Then("my savings account balance should be", -20)
  38:                  .And("my cash account balance should be", 10);
  39:   
  40:  }

How it seems to work:

  • The initial story initialization (lines 8-14) is there to be read by the test reader and to be written to the console. It is the backdrop of this story.
  • There can be several scennarios run inside a single NUnit test
  • There can be several tests for a single scenario (the first scenario here has two tests)
  • When you use a "Given" and "And" you also declare the associated delegate, or actions, that the code should perform. you're basically mapping a piece of test to an action. Later you can reuse that piece of text without needing to declare that action again (see lines 18 and then 25 and then 34). This is essentially creating a DSL (Domain specific language) to be used in the scenario tests.
  • The full test and its output can be seen here. the output is very detailed. I'm not sure if you see it also when the tests pass or only if they fail. In any case, it's very verbose and I think should show only when failing.

My notes(and Joe's answers to them in a newly posted entry):

  • Would be nice to incorporate this into other frameworks like RhinoMocks, or even to non test-related frameworks, to make them self-testing.
  • This is a nice API for any behavior-driven code. I'd use it in some sort of a rules engine (some modified version of it) for basic readable rule declaration.
  • You actually write your own DSL here, which is nice, but it's still developer facing. customers can't deal with this. too technical. I can't hel pbut think that this is exacly the kind of DSL that is enabled by using Fitnesse along with the DoFixture. I'm not sure duplicainog is a good thing here but I'm willing to live with the two in separate until something better that unites them comes along.
  • Would be nice to have a way to declare some sort of "initalizationTest" where you place all the strings with related delgates into. Wait, there is - use [SetUp]. But still feels clunky.
  • Many strings also means ability to fail in use the right string: maybe use consts but then, that would defeat the purpose... not sure what the best solution here.
  • I'm not sure that using delegates is the right way to go here. Maybe using actual method references instead of anonymous delegates is better (they are utility methods anyway. Still not sure which would be more readable.
  • using "then" and "And" means you can have multiple "Asserts" on a given scenario test. I think that also means you get the problem associated with using multiple asserts in a single test. I'm not sure if the frameworks helps "swallow" exceptions and moves on to the next asserts or if each exception blows up the entire test. ( so if line 21 throws an exception , will line 22 ever execute?)
  • I think this syntax will be largely unreadable in VB.NET, which is much more verbose.
  • Maybe there cold be a tool who would let you write these sentences in excel and then "transfer" them into c# code. that'd be awesome. especially if it was automatic. that might be the bridge to fitnesse I'm looking for.

Over all I think the API is very nice. Readable. I like how it "behaves" if you will. It is still rough around the edges, but assuming its already usable and no seious bugs, the only real possible problem may be the "multiple asserts" thing, which I'm not sure is really a problem. But what might inhibit a team fro using it?

  • Developers who are already used to the NUnit syntax might dislike this syntax or "not get it"
  • People might think that these tests are not instead of other unit tests - "More tests to write??"
  • People may not know when to use Behave# over regular unit tests - there should be some simple guidelines on when to use which.
  • Still today, many developers are not comfortable with using anonymous delegates.
  • afraid to use it since its so new and only one developer supports it.

I think this is a good opportunity to start a real conversation about BDD.

  • Is BDD testing just unit testing with a more "natural" syntax? Right now it seems to be.
  • Should BDD separate into developer-facing and customer-facing tests? (behave# vs. fitnesse)
  • If not, how do we combine these?
  • it seems that BDD can be used bot for unit testing and integration testing. It blurs the lines between traditional unit testing concepts and integration tests, or, just gives some sort of unified language to do both. it's still up to us to decide what kind of test we'd like to write.
  • What types of tests is BDD not good for?
  • What other questions should we be asking?
Published Saturday, August 04, 2007 7:51 AM by RoyOsherove

Comments

Saturday, August 04, 2007 8:03 AM by Joe Ocampo

# re: Behave# enables Behavior Driven Testing, raises some interesting questions

Wow! Thanks for the feedback.

A posts I did a while back answers a couple of your questions.

www.lostechies.com/.../more-bdd-xbehave-madness.aspx

But I will definately follow up with a post to answer the remaining.

Sunday, August 05, 2007 4:06 AM by Morgan

# re: Behave# enables Behavior Driven Testing, raises some interesting questions

First, BDD should not be used instead of TDD. As Dan North explained it, with BDD you specify the behaviour looking at the system from the ouside.

When you then implement the stuff and get "deeper" into the code you will use your TDD skills as usual.

BDD should be used to connect developers and business people, imho this is where the main benefit of BDD is,

you dont need a framework for that but we develeopers can't help it, when things are organised we think "hey, I can implement this in code" :) The BDD frameworks only add another benefit, an executable spec.

If both "camps" can speak in terms of Given/When/Then with each other about the features to implement they will connect better.

And finally, I don't really get why it should be unreadable in VB.NET?

The story would look something like:

       Story("Transfer to cash account"). _

           AsA("Bank card holder"). _

           IWant("to transfer money from my savings account"). _

           SoThat("I can get cash easily from an ATM")

Sunday, August 05, 2007 9:58 PM by Jimmy Bogard

# re: Behave# enables Behavior Driven Testing, raises some interesting questions

That is a lot of great feedback!  Joe and I have had a few conversations about many of the points you've brought up.  Behave# is still in its infancy, so questions like these will definitely help in shaping its role and direction.  We're going to release a vision statement soon that should hopefully clarify the purpose and scope of Behave#.  Thanks again for the feedback!

Monday, August 06, 2007 5:46 AM by Mark Seemann

# re: Behave# enables Behavior Driven Testing, raises some interesting questions

Morgan's comment almost answers the question on when to use BDD versus TDD: To me, BDD is about capturing use cases/stories in an automatable, repeatable fashion.

If you look at a typical componentized ('layered') application architecture, it only makes sense to apply BDD to components that are very close to the application perimeter: UI Controllers/Façades/etc. Such components typically exist for the one purpose of wiring up an external interface (UI/Service Interface) to the rest of the application, so they most closely resemble the business needs.

One of the tricky parts of software development (particularly OOD) is decomposing all the different concerns of an application into autonomous units. While doing that, we also create a level of abstraction (data access components, interfaces, logging strategies, what have you) that removes most of the code quite far from the business requirements.

As such, unit testing is the only sort of test that makes sense at that level, since you can't map a business requirement entirely to any single component. This means that in essense, a behavioral test is a sort of integration test.

In agile projects, this approach is still valuable, since we should never write code for which there is no business requirement. You could actually take this further and enable code coverage on your behavioral tests: If you have code that's not covered, you either need to write a test, or that code should not be there. That may sound familiar to anyone used to TDD, but the difference is that 'normal' unit tests don't count: Only behavioral tests count towards 'requirments coverage'.

That's probably taking things a bit too far, but it's an intriguing idea :)

Monday, August 06, 2007 2:38 PM by Gil Zilberfeld

# re: Behave# enables Behavior Driven Testing, raises some interesting questions

While I agree with the distinction that was discussed above, there is something to be said regarding abstraction in the developer realm.

BDD allows you to specify how the system should behave. It's use is customer facing. But wouldn't you want the developer to also use this as an abstraction? Fluent interface is already in use in NUnit, making the tests more readable. Why not take the next step (I know it looks like sci-fi today) and abstract the component (or service provider) with similar taxonomy?

If we leave APIs out of the discussion, we are talking about two languages (DevSpeak and CustomerSpeak) that may someday, with the right tools converge.

</Prophecy>

Gil

Tuesday, August 07, 2007 11:26 AM by Jimmy Bogard

# re: Behave# enables Behavior Driven Testing, raises some interesting questions

I elaborated some more on a few of your concerns:

grabbagoft.blogspot.com/.../addressing-some-behave-concerns.html

Thanks again for the feedback!

Tuesday, August 07, 2007 12:07 PM by Joe Ocampo

# re: Behave# enables Behavior Driven Testing, raises some interesting questions

I answered your questions and concerns here:

www.lostechies.com/.../attempting-to-demystify-behavior-driven-development.aspx

Thanks you for the feedback!

Thursday, March 27, 2008 5:54 PM by GrabBag

# Addressing some Behave# concerns

This post was originally published here . So Joe and I have received some initial feedback for Behave#