24

I am trying to understand BDD. I've read some articles and as I understood BDD is "the next step" from TDD. I say that because I find both to be very similar, and as I could read in this article, BDD was born as an improvement from TDD. Great, I really like the idea.

There is one practical point that I do not get, though: there is a .feature file in which the BA will write all the expected behavior in the system. As a BA, he has no idea how the system is built, so we will write something like this:

+Scenario 1: Account is in credit+
Given the account is in credit
And the card is valid
And the dispenser contains cash
When the customer requests cash
Then ensure the account is debited And ensure cash is dispensed
And ensure the card is returned

Ok, this is great, but there are many parts of the system that will collaborate so that it can happen (think of Account obj, Dispenser obj, Customer obj and so on). To me this looks like an integration test.

I would like to have Unit Tests. How do I test the code that checks if the dispenser has money? Or that the cash is dispensed? Or that the account is debited when required? How can I mix unit tests with "BA Created" tests?

6
  • That's what mocks and stubs are for: to isolate the parts under tests. Feb 26, 2015 at 15:10
  • Sorry, I dont get it. You mean I should mock the dispenser? How would I test it?
    – JSBach
    Feb 26, 2015 at 15:12
  • When you're testing the dispenser, you mock the account, card and customer. Feb 26, 2015 at 15:39
  • 4
    Why do you want to mix unit tests and "BA created tests"? Use TDD as a technique to create unit tests for individual parts of your software, and add additional tests for testing the requirements from the BA's point of view (call the latter integration tests, if you like). Where do you see a contradiction?
    – Doc Brown
    Feb 26, 2015 at 15:43
  • @DocBrown: By "naturally emerge," I mean that some TDD'ers believe that a software design will naturally emerge from the unit tests as you "red-green-refactor." Ongoing chat conversation about this question is taking place in The Whiteboard. Feb 26, 2015 at 16:04

4 Answers 4

34

Behavior Driven Development and Test Driven Development are complimentary, but not a replacement for each other.

How the application "behaves" is described in Acceptance Tests, which according to BDD would be the Features and Scenarios written in Cucumber.

The nitty gritty details of how each small component works are described in Unit Tests. The outcomes of the Unit Tests support the Scenarios you write in Cucumber.

Imagine the process for building a car.

First, the product team comes up with their ideas, and eventually boil them down to usage scenarios:

Scenario: Starting the car
    Given I am standing in front of the drivers door
    When I open the door
    Then the door should lift up DeLorean-style (yeah, baby!)
    When I get into the car
    And turn the key
    Then the engine roars to life

I know this scenario sounds a bit silly, but it is a very high level, product and end user focused requirement. Just opening the door, turning the key and starting the engine involves a LOT of different components working together. This one test is not enough to make sure the vehicle works properly. You need to test the starter, the battery, the alternator, key, ignition switch --- and the list goes on --- just to get into the car and start it. Each of those components need their own tests.

The scenario above is a "Big Picture" test. Each component of the vehicle needs "Small Picture" tests to make sure they function properly within the whole.

Building and testing software is the same in many respects. You design from top down, then build from bottom up. Why have a door that lifts up if you can't even start the engine? Why have a starter if you have no battery?

Your product team will come up with the Acceptance Tests and flesh them out in Cucumber. This gives you the "Big Picture". Now it's up to the engineering team to design the proper components, and how they interact, then test each one separately --- these are your Unit Tests.

Once the Unit Tests are passing, start implementing the Cucumber scenarios. Once those are passing, you have delivered what the product team has asked.

4
  • Is there a way to link those "Big Picture" tests with "Small Picture" tests? I mean, when features officially change (say a changing cucumber scenario), is there a way to map that change to the low end tests (say junit tests that are for that particular cucumber scenario)?
    – Srikanth
    Sep 9, 2015 at 3:13
  • You can have helper methods and custom assertions shared between your "big picture" and "small picture" tests, but they will most likely involve different setup to test specific units of code. Nov 22, 2015 at 18:41
  • [...] which according to BDD would be the Features and Scenarios written in Cucumber. You're conflating principles and tooling.
    – jub0bs
    Apr 28, 2016 at 10:38
  • Well, Ok, the wording is a little off, but the point is the behavior of an application is captured in the features and scenarios. Apr 28, 2016 at 12:35
16

I am trying to understand BDD. I've read some articles and as I understood BDD is "the next step" from TDD. I say that because I find both to be very similar, and as I could read in this article, BDD was born as an improvement from TDD.

Actually, no, BDD is not "the next step" from TDD. It is TDD. Or more precisely, it is a rephrasing of TDD.

The creators of BDD noticed that the major hurdle to understanding that TDD is not about testing but about behavioral specification was that all the TDD terminology is about testing and not about behavioral specification. It's like trying not to think of a pink elephant when someone says to you "try not to think of a pink elephant", except with the added complication of being in a room full of pink elephants and a guy constantly yelling "pink elephant, pink elephant, pink elephant" in your ear.

So, they rephrased TDD in terms of behavioral specification. "Tests" and "test cases" are now "examples", "units" are "behaviors", "assertions" are "expectations", and so on.

However, the methodology is still the same. You start with an acceptance test (I mean "feature"), zoom in to a unit test (I mean "example"), zoom back out etc.

I would like to have Unit Tests. How do I test the code that checks if the dispenser has money? Or that the cash is dispensed? Or that the account is debited when required? How can I mix unit tests with "BA Created" tests?

The same way you do in TDD. You can write your features and your examples in different frameworks (e.g. Cucumber and RSpec) or even different languages (e.g. writing examples for a C project in C, and features in FIT/Fitnesse), you can use a single features framework for both (e.g. writing examples and features in Cucumber) or you can use single examples framework for both (e.g. writing both in RSpec). You don't even have to use a framework at all.

An example of TDD-done-right (which is identical to BDD) using just a single framework is JUnit itself, which contains a mixture of unit tests (examples) and functional / integration tests (features), all written in JUnit itself.

I believe Kent Beck calls this "zooming". Start high-level, then "zoom in" to the details, then back out again.

1

Disclaimer: I am not an expert in BDD, but I try to give you my point of view on the article you linked to.

TDD is an implementation technique - you first write a test, then you implement the method, run your test, refactor, and add further tests for the same method or for a new method. TDD does actually not define any rules for how to choose class or method names, that's up to you. TDD also does not tell you "when you are done".

So whenever you write a test for a new method, you have to choose a method name - and that is the point where BDD comes in. By choosing method names using the business terms from the scenario above, and by choosing them in a way describing the behaviour of your class, you are doing BDD. Whenever you ask yourself "do I have to add further tests", you can look the the scenarios given by your BA and check if you have implemented all the needed parts them completely. If not, you will need to add more tests.

The author of the article also suggest to use a more behaviour-related naming scheme when choosing the names of your tests, that's why he suggests to replace JUnit by a tool which does not rely on a naming scheme where each test case has to start with the name "test". Though I don't know JBehave, I think that's the main difference between that tool and Junit.

Moreover, the BDD scenarios will also be a blueprint for integration tests - which you will typically add after you have fleshed out the method names by TDD and after you added a reasonable amount of unit tests.

So, to my understanding, TDD is an instrument you can use as part of BDD, and BDD helps you to write the right tests and give them better names.

3
  • As a quick point, Junit supports naming your tests anything; you just have to use a @Test annotation. It may not have done back in 2003 though.
    – soru
    Feb 27, 2015 at 18:27
  • @soru Back in 2003 it did indeed enforce the word "test".
    – Lunivore
    Apr 17, 2015 at 15:59
  • The author of the article is Dan North, who came up with the concept in the first place. One of the things he noticed is that the word "test" causes us to move to testing our implementation (solution domain) whereas actually, exploring and defining tests should really keep us in the problem domain. Dan has described BDD as "what TDD was meant to be". Read this for more info: dannorth.net/2012/05/31/bdd-is-like-tdd-if
    – Lunivore
    Apr 17, 2015 at 16:01
0

BDD is a mindset for TDD done right. Well, not only TDD but unit testing in general.

Later BDD became a base for Acceptance Tests written in Gerkin or SpecFlow (domain language in free text). But this is OPTIONAL. In fact, in 90% of cases using extra tools for ".feature files" is a waste (because in reality business people never read them).

So, don't use ".feature files"! Don't ask BAs to write them. Your BA (or better, product manager or product owner) should write User Stories, that your team will translate into tests (i.e. unit tests and integration tests in your programming language with bdd style). So, Write with BDD style in your programming language.

Last thing, when your test spans several components you have to write 2 test:

  1. unit tests, when everything external to the module is mocked and only statuses are checked (chicago school); In unit tests avoid mocks for the internals (it will make your tests fragile and hard to maintain. Well mocking internals will handicap your possibilities to refactor the code under test. While real test let you refactor SUT easily );
  2. system test (acceptance test, end-to-end) that is run on the running, integated system and real components are tested. But this tests should be minimal, smoke tests really. E2E tests are fragile and harder. It's easier to check everything in "isolated integration tests" really.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.