Attempting to Demystify Behavior Driven Development


After receiving several emails and reading Roy Osherove’s post on Behave#, I wanted to give more incite and answer some questions that were asked about Behave# and BDD in general.

What is BDD?

I am really going to do one hell of a hack job on Behavior-Driven.org but my intentions are to draw you to the issue at hand.

Behavior Driven Development’s (BDD) primary intent is to bring software development’s focus back to the delivery of business value.  It accomplishes this by bridging the dichotomy **between **business requirements and working software into one cohesive common vocabulary called the ubiquitous language.

Now it is very important to note that BDD is simply the evolution of the existing practice of Test Driven Development (TDD). A majority if not all of the principles of TDD are still applicable. BDD merely focuses on the vocabulary on which these principles are conveyed that is meaningful both to the business advocates as well as the development and testing teams.

Experienced TDD practitioners, particularly those that have been involved in helping other developers learn the practice are accustomed to the following epiphanies:

  1. The developer starts writing unit tests around their code using a test framework like JUnit or NUnit.
    • As the body of tests increases the developer begins to enjoy a strongly increased sense of confidence in their work.
      • At some point the developer has the insight (or are shown) that writing the tests before writing the code, helps them focus on only writing the code that they need.
        • The developer also notices that when they return to some code that they haven’t seen for a while, the tests serve to document how the code works.
          • A point of revelation occurs when the developer realizes that writing tests in this way helps them to “discover” the API to their code. TDD has now become a design process.
            • Expertise in TDD begins to dawn at the point where the developer realizes that TDD is not about testing, it is about defining behavior.
              • Behavior is about the interactions between components of the system and so the use of mocking is a fundamental to advanced TDD.</ol> We have observed this progression in many developers, but unfortunately while most, with a little help, find their way to step 4, many miss the big wins found at steps 5, 6 and 7.

              OK so why are steps 5, 6, and 7 so overlooked? Because it requires an understanding of another extremely crucial discipline and that is Domain Driven Design. Domain Driven Design’s focus is to outline a set of design practices and principles centered on the business domain at hand. These practices and principles help to bring attention to the problem business domain through modeling and coding practices.

              Agile principles and practices while not regimented require you to think and determine the best course of action in building great software. They require eXtreme self discipline as they put the power of choice in your hands. If you are putting together a picture frame, bring out the tiny framing hammer. If you are putting down rail road tracks bring out the sledge hammer. The point is, think!

              As usual I digress, Think of BDD as a proverbial facade layer atop your architecture that attempts to bridge TDD, Domain Driven Design and Requirements authoring into one practice. Scott Bellware’s recent post does a better job at explaining this.

              So how do I use it?

              I cannot tell you enough how much I love saying what I am about to say, “It depends…” Being an Agile coach and practitioner that phrase alone has brought frustration and laughter to a majority of my customers. But the phrase truly captures the intention; it really depends on how far you want to take it.

              Where does business software originate? Does it originate in the mind of a developer? A majority of the time software exist to serve the function of facilitating some type of business need. A lot of time that business need is often gathered by formal requirement documents, UML, etc. Sometimes developers never talk to the business (process smell). DDD captures the interaction of the development team in partnership with the business, to come up with a domain model that they both agree on, both in definition and in structure. The model is captured in the Domain Layer and forms the heart of architecture. This is where software business objects such as Entities, Value Objects and Services are born. Now notice I said business objects. As the business team and development team interact they form a common vocabulary termed the ubiquitous language. This language helps to explain how our software behaves when the user interacts with the program.  The business team authors stories that are later elucidated by the development team and testers of some kind.  These stories take on the following form.

              See What’s in a Story?

              From the Domain layer you capture a story with the business user. In fact if you can have them write the story and the acceptance test.

              As a savings account holder
              I want to transfer money from my savings account
              So that I can get cash easily from an ATM

              Create a couple of acceptance test.

              Scenario 1: Savings account is in credit
              Given my savings account balance is: 100
              And my cash account balance is: 10
              When I transfer to cash account: 20
              Then my savings account balance should be: 80
              And my cash account balance should be: 30

              Scenario 2: Savings account is overdrawn
              Given my savings account balance is: -20
              And my cash account balance is: 10
              When I transfer to cash account: 20
              Then my savings account balance should be: -20
              And my cash account balance should be: 10

              OK you have a story and some acceptance test, so you can tell when the story complete.

              So if we were using NUnit we could write a simple unit test like this.

              [TestFixture]
              public class AccountTests
              {
                  [Test]
                  public void TransferFunds()
                  {
                      Account savingsAccount = new Account(100);
                      Account cashAccount = new Account(10);
                      savingsAccount.TransferTo(cashAccount, 10);         Assert.AreEqual(90, savingsAccount.Balance);
                      Assert.AreEqual(20, cashAccount.Balance);
                  }
              }

              Assuming you were practicing TDD you went through the steps of Red, Green and Refactor. Now you are on your way to TDD Nirvana but wait. You have completed your first Unit test but the problem is that it means only something to you the developer. It does not have any meaning to the business, all they care about is that the software working? Before I get bombarded by emails, you could be blessed with an uber business analyst that can write FitNesse fixtures. I have never been blessed with such an individual so for those that have, kudos to you! A majority of the business users I deal with love to author stories but they don’t like to work with tools that cause them to change their chain of thought.

              So lets dress this up a little bit with some BDD flavor.  Mind you we are still using NUnit!

              [TestFixture]
              [Category(“Account Specifications”)]
              public class When_transferring_money_to_a_cash_account_from_a_savings_account_in_credit
              {
                  private Account savingsAccount = new Account(100);
                  private Account cashAccount = new Account(10);
                  [SetUp]
                  public void Given()
                  {
                      savingsAccount = new Account(100);
                      cashAccount = new Account(10);
                      savingsAccount.TransferTo(cashAccount, 10);
                  }
                 
                  [Test]
                  public void Then_savings_account_balance_should_be_90()
                  {
                      Assert.That(savingsAccount.Balance, Is.EqualTo(90));
                  } 
                  [Test]
                  public void Then_cash_account_balance_should_be_20()
                  {
                      Assert.That(cashAccount.Balance, Is.EqualTo(20));
                  }
              }

              As you can see this is the same test but it reads much cleaner.  I use the class name to indicate the “When” of BDD, I then use the SetUp to control the contextual flow of the test fixture, the “Given”.  SetUp actually means something now from a contextual flow, it sets up the “Given(s)” and invokes the “When”.  The only aspect remaining is to assert on the behavior that should happen when we transfer to an account. In this case the savings account balance should be 90 and the cash account balance should be 20. 

              I encourage everyone that is practicing TDD or BDD and using NUnit 2.4 or above to start using the new constraint model.

              So what have we achieved here?  We have taken an existing TDD unit test and transformed it into a more meaningful representation of intent and behavior by applying the Given, When, Then constructs of BDD.  No existing frameworks were harmed in the production of this unit test.  Just simply a state of mind change.  This verboseness and readability have tremendous implications as the test runner displays the following output.

              image 

              Here is the same result set grouped by category.

              BDDRunnerOutputCatagory

              This is nice, I get to ask you a couple of questions.

              • What is purpose of AccountTests?
                • What is the test TransferFunds doing?
                  • What happens when you transfer money to a cash account from a savings account in credit?</ul> Hmm the last question kind of matches the behavior of the fixture perfectly! Simply magical, you can easily see that the output of your unit test have business meaning!  They can be used to convey the behavior of your software and the business value that it is producing.  Because most xUnit framework produce some type of XML file you can use an XSLT file to transform the raw output into something meaningful for the business.  Do a simple underscore to space replacement and you have yourself a talking requirements document!  I have heard of tails of uber developers that have managed to reflect their way to this state of nirvana by the source code alone but I have yet to see any post on such a mystical endeavor. hint hint!  Update: mystical tool has been found!

                  Ok this is great Joe, so why on earth would we need Behave# if we simply have to change our thought process around TDD?

                  I am glad you asked! 

                  The answer to this questions lies in the source code.  Look again at the BDD fixture we created above.

                  [TestFixture]
                  [Category(“Account Specifications”)]
                  public class When_transferring_money_to_a_cash_account_from_a_savings_account_in_credit
                  {
                      private Account savingsAccount = new Account(100);
                      private Account cashAccount = new Account(10);
                      [SetUp]
                      public void Given()
                      {
                          savingsAccount = new Account(100);
                          cashAccount = new Account(10);
                          savingsAccount.TransferTo(cashAccount, 10);
                      }
                     
                      [Test]
                      public void Then_savings_account_balance_should_be_90()
                      {
                          Assert.That(savingsAccount.Balance, Is.EqualTo(90));
                      } 
                      [Test]
                      public void Then_cash_account_balance_should_be_20()
                      {
                          Assert.That(cashAccount.Balance, Is.EqualTo(20));
                      }
                  }

                  Question time! Looking at the code above:

                  • What type of profession can author the scenario above?
                    • Can a business person write this?
                      • From a traceability perspective what story spawned this scenario?
                        • Why do these objects even exist?</ul> Answers:

                        • Developer

                          • Not a chance
                            • Don’t know?
                              • Because I wrote them!</ul> Enter in Behave#.  Now I have proven the probability of a Business Analyst being able to use Behave# don’t ask me why but it was easier to show them how to use Behave# then it was FitNesse.  I am not taking anything away from FitNesse I am simply conveying the outcome of this ONE episode I had in teaching someone how to author a story in an IDE that had never used one.  I will say that I have spent the last 2 years preaching about story form and acceptance test authoring, so that probably gave this Business analyst an edge over the rest of her peers.  The code below gives you an example of how the story and scenarios fit together in Behave#.

                              Business Authors:

                                     [Test]
                                      public void Transfer_to_cash_account()
                                      {
                                          Story transfer_to_cash_account = new Story(“Transfer to cash account”);

                                          transfer_to_cash_account.As_a(“savings account holder”)
                                              .I_want(“to transfer money from my savings account”)
                                              .So_that(“I can get cash easily from an ATM”);
                                          Scenario savings_account_is_in_credit = new Scenario(“savings account is in credit”);             savings_account_is_in_credit
                                              .Given(“my savings account balance is”, 100)
                                              .And(“my cash account balance is”, 10)
                                              .When(“I transfer to cash account”, 20)
                                              .Then(“my savings account balance should be”, 80)
                                              .And(“my cash account balance should be”, 30);
                                          savings_account_is_in_credit
                                              .Given(“my savings account balance is”, 400)
                                              .And(“my cash account balance is”, 100)
                                              .When(“I transfer to cash account”, 100)
                                              .Then(“my savings account balance should be”, 300)
                                              .And(“my cash account balance should be”, 200);
                                      }

                               

                              Developer Implements action delegates:   

                                      [Test]
                                      public void Transfer_to_cash_account()
                                      {
                                          Story transfer_to_cash_account = new Story(“Transfer to cash account”);
                                          transfer_to_cash_account.As_a(“savings account holder”)
                                              .I_want(“to transfer money from my savings account”)
                                              .So_that(“I can get cash easily from an ATM”);
                                          Account savings = null;
                                          Account cash = null;
                                          Scenario savings_account_is_in_credit = new Scenario(“savings account is in credit”);
                                          savings_account_is_in_credit
                                              .Given(“my savings account balance is”, 100,
                                                     delegate(int accountBallance)
                                                         {
                                                             savings = new Account(accountBallance);
                                                         })
                                              .And(“my cash account balance is”, 10,
                                                   delegate(int accountBallance)
                                                       {
                                                           cash = new Account(accountBallance);
                                                       })
                                              .When(“I transfer to cash account”, 20,
                                                    delegate(int transferAmount)
                                                        {
                                                            savings.TransferTo(cash, transferAmount);
                                                        })
                                              .Then(“my savings account balance should be”, 80,
                                                    delegate(int expectedBallance)
                                                        {
                                                            Assert.AreEqual(expectedBallance, savings.Ballance);
                                                        })
                                              .And(“my cash account balance should be”, 30,
                                                   delegate(int expectedBallance)
                                                       {
                                                           Assert.AreEqual(expectedBallance, cash.Ballance);
                                                       });
                                          savings_account_is_in_credit
                                              .Given(“my savings account balance is”, 400)
                                              .And(“my cash account balance is”, 100)
                                              .When(“I transfer to cash account”, 100)
                                              .Then(“my savings account balance should be”, 300)
                                              .And(“my cash account balance should be”, 200);
                                      }

                              Lets ask the questions again! Looking at the code above:

                              • What type of profession can author the scenario above?
                                • Can a business person write this?
                                  • From a traceability perspective what story spawned this scenario?
                                    • Why do these objects even exist?</ul> Answers:

                                    • Developer possibly a business analyst of some kind. 

                                      • Maybe
                                        • Story: Transfer to cash account: As a savings account holder I want to transfer money from my savings account So that I can get cash easily from an ATM
                                          • Because the preceding story and the scenario expect it.</ul> As you can see Behave# manages to plug the holes that basic test fixture was missing.  More importantly it engage the product owner(the business) to be actively involved in the story authoring process within the source code.  Not word document or some UML diagram but the actual source code!

                                          Here are some of the questions that have been asked about Behave#:

                                          Roy Osherove’s notes and questions

                                          1. Would be nice to incorporate this into other frameworks like RhinoMocks, or even to non test-related frameworks, to make them self-testing.
                                            1. Agreed although I don’t know how Ayende may feel about it.  But then again Rhino does mocking and Behave# does BDD.  Think SRP on a grander scale.
                                              • 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 help but think that this is exactly the kind of DSL that is enabled by using Fitnesse along with the DoFixture. I’m not sure duplication is a good thing here but I’m willing to live with the two in separate until something better that unites them comes along.
                                              1. I will have to look into the DoFixture syntax but I find it hard to believe that they took this route.
                                                • 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.
                                                1. You could to this, I even experimented with creating my own Acceptance test class that simply exposed static methods that mapped to the action delegate signature and performed the assertion.  Anything really is possible since it simply is a closed statement block that can be implemented inline or within a class or fixture itself. You see clunky I see options.  🙂 You could place all the strings in the setup but you are thinking like a developer.  Business analyst won’t do this but they sure love to copy and paste! 
                                                  • 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.
                                                  1. Agreed, I am spiking a simple distance algorithm to take care of typos or accidental space inclusion.  This should help in that arena. But I firmly believe that the business analyst should be allowed to use strings, that is the power of framework.  By holding strict to modern OOP practices we will hinder the authorship of the story from the business analyst perspective.
                                                    • 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.
                                                    1. See answer to question 3.
                                                      • 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?)
                                                      1. At this time no it will not ever reach line 22 but the intention is that the stacktrace is written in such a verbose manner that it will logically bring the developer to the point of contention and solve this issue as it relates to the context of scenario being exercised.
                                                        • I think this syntax will be largely unreadable in VB.NET, which is much more verbose.
                                                        1. With the exception of underscores the authoring should be fairly easy but I do agree that wiring up the delegate will not be as elegant.  I have an idea stop using VB.Net.  Just kidding but I strongly encourage VB.Neters to switch to C# or if you like your code switch to IronRuby!.
                                                          • 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.
                                                          1. Funny you should ask.  This is the first time I am going to say this so I am kind of disappointed that it is buried in here but it should answer your question.  My thought was to contact Dan North and other BDD practioners to come up with an XSD that can carry the information of defining Stories, Scenarios, and Actions.  This meta data would then becomes a lightweight payload that can be shared between other applications.  Imagine, now you could create you own story authoring template in Word, Excel , you could even imbed a rich text box in your favorite agile project management tool and export the information to a validation framework such as behave# or what ever parser you would like.  Again this is conceptual thought but I am sure you see the potential.
                                                            • Developers who are already used to the NUnit syntax might dislike this syntax or “not get it”
                                                            1. Agreed that the BDD syntax takes a while to get use to but so did TDD.  I read somewhere we should Embrace Change and be courageous. 🙂 
                                                              • People might think that these tests are not instead of other unit tests – “More tests to write??”
                                                              1. Like any other practice this is going to take time and I don’t want anyone to throw away there existing test suite to write them over in a BDD context.  Take for instance where I work.  We have over 6000 unit test covering our solution.  Do you honestly think we are going to change all of them, no.  What we are doing is any enhancements or refactorings that are being accomplished are being written in BDD syntax.  I made a special point to tell my development staff not to move to BDD unless they felt completely comfortable or were pairing with someone who had already done this.  Like all agile practices it is organically taking shape and proliferating itself throughout the development team.  But to your point, yes they did think at first that they were going to have to write more tests and in fact they have but they are amazed that they can actually find meaning in the code now.
                                                                • People may not know when to use Behave# over regular unit tests – there should be some simple guidelines on when to use which.
                                                                1. Agreed, the most logical place to start using Behave# is at the Domain Model layer.  Simply because it lends itself to defining the behavior of the domain model as it relates to stories and scenarios.  It can be used at lower level layers but I have found confusion amongst developers when pursuing it at that level.  I don’t think it is particular to behave# as much as it is to BDD in general.  I would consider Behave# to be more of an acceptance testing framework (at this time) simply because of cultural barriers.
                                                                  • Still today, many developers are not comfortable with using anonymous delegates.
                                                                  1. _Hmmm…Since they have been around since version 2.0 I am astonished especially since allot of the generic constructs in C# 2.0 depend on them.  Not to mention 3.5 Lambda expressions.  Jimmy pointed out to me that when 3.5 comes out we can simply overload the action delegates with funct and use Lambda expressions as well.  I had no clue about developers being uncomfortable though.  Do you know why they are not comfortable with them?_
                                                                    • afraid to use it since its so new and only one developer supports it.
                                                                    1. JUnit and NUnit were new at one point.  🙂  Update: About the one developer Jimmy Bogard has had a huge impact on this project.  So as of today the developer contribution is 2.  Like Jimmy mentions more than one == Open Source Support.  🙂
                                                                      • Is BDD testing just unit testing with a more “natural” syntax? Right now it seems to be.
                                                                      1. Partly correct but so much more. Hopefully if you are still reading this I have answered this question in the sections entitled “what is BDD” and “How do I use it.”
                                                                        • Should BDD separate into developer-facing and customer-facing tests? (behave# vs. fitnesse)
                                                                        1. No No No…I don’t want to have a separation of concern any longer. Behave# should be seen as a starting point within the actual code implementation.
                                                                          • If not, how do we combine these?
                                                                          1. Use Behave#
                                                                            • 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.
                                                                            1. Exactly!
                                                                              • What types of tests is BDD not good for?
                                                                              1. I can’t think of any.  For the most part all test have a context and an assertion on the correct or incorrect behavior of that context.</ol>
Los Techies Welcomes Marcus Bratton