Since there are a few debates going on (again!) about whether BDD is just TDD done well, I thought it might be interesting to showcase some examples where BDD language made a difference to people’s understanding.
From StackOverflow, TDD – Should Private/Protected methods be under unit test?:
Original Poster wrote:
In TDD development, the first thing you typically do is to create your interface and then begin writing your unit tests against that interface. As you progress through the TDD process you would end-up creating a class that implements the interface and then at some point your unit test would pass.
I wrote: Please let me rephrase this in BDD language:
When describing why a class is valuable and how it behaves, the first thing you typically do is to create an example of how to use the class, often via its interface*. As you add desired behavior you end up creating a class which provides that value, and then at some point your example works.
*May be an actual Interface or simply the accessible API of the class, eg: Ruby doesn’t have interfaces.
This is why you don’t test private methods – because a test is an example of how to use the class, and you can’t actually use them.
Response: Brilliant post. Clarifies a lot.
From StackOverflow, should i only be testing public interfaces in BDD (in general, and specifically in ruby) (sic):
Instead of writing a test, you’re going to write an example of how you can use your class (and you can’t use it except through public methods). You’re going to show why your class is valuable to other classes. You’re defining the scope of your class’s responsibilities, while showing (through mocks) what responsibilities are delegated elsewhere.
At the same time, you can question whether the responsibilities are appropriate, and tune the methods on your class to be as intuitively usable as possible. You’re looking for code which is easy to understand and use, rather than code which is easy to write.
If you can think in terms of examples and providing value through behaviour, you’ll create code that’s easy to use, with examples and descriptions that other people can follow. You’ll make your code safe and easy to change. If you think about testing, you’ll pin it down so that nobody can break it. You’ll make it hard to change.
Response: good answer! very concise!
From comments on my blog post, “Translating TDD to BDD”:
Ben asked: Given this terminology, can you reword these sentences to eliminate the TDD terminology, but in such a way that someone who doesn’t know what BDD is can understand it?
Writing the tests first ensures that the code we write to make them pass is actually testable. Otherwise, we may wind up with classes and methods that, although fairly well designed, are not easily tested
Writing examples of how to use the code, before we write the code that makes those examples work, ensures that the code we write is easy to use and understand. Otherwise, we may wind up with code that, although adhering to SOLID principles, has been written to be easy to write rather than easy to use or maintain.
(Of course, if you’re doing true outside-in then you already have one example of how to use a piece of code, from its consuming class. I reworded this from ‘well-designed’ to ‘adhering to SOLID principles’, since they’re necessary for good design but IMHO not sufficient.)
Ben responded: Liz, that’s beautiful. I especially like how you phrased your points about use and maintenance. Takes the focus off “testing” and puts it on something that’s more directly tied to value.
Taking it up a level, again from StackOverflow, Are BDD tests acceptance tests?
BDD “tests” exist at multiple different levels of granularity, all the way up to the initial project vision. Most people know about the scenarios. A few people remember that BDD started off with the word “should” as a replacement for JUnit’s “test” – as a replacement for TDD. The reason I put “tests” in quotes is because BDD isn’t really about testing; it’s focused on finding the places where there’s a lack or mismatch of understanding.
Because of that focus, the conversations are much more important than the BDD tools.
Acceptance testing doesn’t actually mandate the conversations, and usually works from the assumption that the tests you’re writing are the right tests. In BDD we assume that we don’t know what we’re doing (and probably don’t know that we don’t know). This is why we use things like “Given, When, Then” – so that we can have conversations around the scenarios and / or unit-level examples.
We don’t call them “acceptance tests” because you can’t ask a business person “Please help me with my acceptance test”. Try “I’d like to talk to you about the scenario where…” instead. Or, “Can you give me an example?” Either of these are good. Calling them “Acceptance tests” starts making people think that you’re actually doing testing, which would imply that you know what you’re doing and just want to make sure you’ve done it. At that point, conversations tend to focus on how quickly you can get the wrong thing out, instead of about the fact you’re getting out the wrong thing.
Response: 20 upvotes and a “nice answer” badge!
These are just a few instances of using BDD’s language instead of TDD’s. I’ve found it even more powerful in spoken language, and more powerful still when talking to business-focused stakeholders about examples of how we might use a system to deliver the value they want. I taught BDD to my dad once, showing him how to write examples in Java in order to ensure that his code would be usable and maintainable. After we’d written a couple of classes, I said, “Of course, this also gives you a nice set of regression tests.”
“Oh, yes!” he said, “So it does. I hadn’t thought of that.”
Great collection! I’ll keep it and give the link to all the people who use cucumber for testing only:-)
Thanks, keep up the great work!
Pingback: BDD is like TDD if… « DanNorth.net
So very sad. WordPress discarded my comment during the log-in phase. Just one more reason I don’t use WordPress for my blogs. And, a brilliant example of a regression that TDD/BDD would have addressed before I discovered this bug.
As I intended to post originally, . . .
In TDD development, the first thing you typically do is to create your interface and then begin writing your unit tests against that interface.” — this belies a fundamental misunderstanding of what TDD is. You don’t conceive of the interface first. You write the TESTS first, and let the interface “evolve” organically. Kent Beck wrote several BOOKS basically attempting to drive this point home. I can’t fathom how or why this has gone so long without being understood.
I’m glad that the BDD movement has provided (in essence) a pattern language encapsulating this practice. People thoroughly misunderstood the intent behind TDD and focused on the mechanics rather than the desired outcome.
Personally, I never use a BDD framework, only because I don’t like heaping dependencies on my projects, and I find non-technical staff can’t really understand them any more than looking at raw C. But I study BDD trends and apply them in my normal TDD development. It’s what Beck wanted (but failed) to communicate, and it’s just the right thing to do.
Hi, your original comment wasn’t lost (I’ve trashed it as it duplicated this one). It was just awaiting moderation by me.
And thank you for this! The originator of the SO post was obviously doing something that I used to do before I discovered BDD and TDD. Particularly, I remember the moment I discovered that you could create classes and interfaces from within the IDE. It was absolute magic to me at the time and I still remain astounded by it on a regular basis!
Of course, with BDD’s outside-in, I find I rarely create an example with the sole purpose of exploring how a class should be used, as I usually have a class that’s already using it! Though we might make a guess at what that interface is when we describe the delegation behaviour using mocks.
Pingback: BDD is like TDD if… | Programming
For a long time, I had the same repeating discussion with one of the stakeholders of the current company in which I work that it was:
I was exhausted because whatever approach I used, it was impossible to me to change the mind of that stakeholder from the focus of testing methods, to the focus of testing functionalities (behaviours).
Until one day, I came up with the argument: “With TDD, you create the test *before* the code. So, how I can test all methods if they do not exist?”. That was the end of the discussion. After years of discussion, he finally understood that the implementation exists because tests demands for their existence, thus, when they appear they are already tested.