The BDD cargo cult

Posted by aslak.hellesoy

The BDD buzzword (Behaviour-Driven Development) has caught on quite nicely. Unfortunately a lot of people seem to think it’s about syntax, which it is not.

Writing things like context and specify doesn’t mean you’re doing BDD, just like writing tests doesn’t mean you’re doing TDD.

There are other features of RSpec than its syntax that makes it a BDD library.

Expressed intent and Testdox-like reports

Writing specs (or examples or tests) that serve as documentation and at the same time reveal the intent of the code is a common practice among seasoned TDDers. BDD defines this practice as mandatory. RSpec makes the practice easy to follow (using context and specify). The point is – any syntax is fine. You can follow the same practice using FIT or JUnit (or one of the dozens of clones), a naming convention and a reporting tool like Testdox that can generate something like this:


A full stack
- should raise an exception on push
- should allow a pop

RSpec also makes it easier to express intent in the code itself, using constructs like


name.should_match /lak/

Again – this syntax makes it easier to write code that follows the BDD philosophy, but it isn’t – per se – BDD.

Just using context, specify and should_* without understanding that the key points are to express intent and to make it visible won’t bring you more than somewhat nicer syntax. BDD is a technique, not a syntax.

Mock objects

Webster’s definition of “behavior” says: anything that an organism does involving action and response to stimulation.

Code designed according to BDD (at least down at the code level) lets you verify what an object does in response to stimulation (calling a method on it). It’s not about looking at return values from that method. It’s about verifying what other objects the stimulated object communicates with.

This is where mock objects come in. Mock objects (connected to the object you poke at) tells you that. Without mock objects it is terribly hard to know what an object does – you don’t know much about its behaviour. So what a lot of people do instead is to use state-based testing That is fine too, but it ain’t BDD.

So here is an appeal to all of you creating “BDD” libraries: Does your library make it easy to communicate the overall responsibilities of the code? Can you use the library to express behaviour?

If not, chances are you’ve just created an RSpec clone, possibly promoting the BDD cargo cult

Comments

Leave a response

  1. FloehopperDecember 11, 2006 @ 10:46 AM

    It is of course equally possible to write interaction-based tests using Test::Unit and a mocking library.

  2. NeologistDecember 11, 2006 @ 03:38 PM

    “Writing specs (or examples or tests) that serve as documentation and at the same time reveal the intent of the code is a common practice among seasoned TDDers.”

    That’s not just common practice. That IS test-driven development. If you don’t write your tests that way you’re doing testing but your tests aren’t actually driving anything.

    BDD is a cargo cult, maybe. But it’s certainly just rebranding something that already has a perfectly good name with a new, meaningless terminology.

    Behaviour is what is DRIVEN BY THE TESTS. It’s the end result of development. It’s an end, not a means.

  3. Aslak HellesøyDecember 11, 2006 @ 04:58 PM

    Maybe I should have emphasised more: Expressing intent in tests is a common practice among seasoned TDDers. It certainly isn’t common paractice among most people who claim to be doing TDD. I have seen a lot of “TDDed” code that doesn’t express intent or serve as documentation at all.

    I believe the main reason for this is TDD’s unfortunate emphasis on past-tense sounding activities like testing and asserting. People who are new to the practice tend to overlook the more subtle aspects of intent and documentation.

    It is usually the people who “get” TDD that dismiss it as “nothing new”. That’s quite ironic – they ought to realise that everyone is not as bright as themselves, or that they haven’t necessarily had the epiphany yet.

    BDD was created in order to emphasise the values of TDD that apparently are so hard to understand. I don’t think BDD is a cargo cult, but I think that a lot of the people who have jumped on the BDD band wagon are missing the point.

    Others (usually the ones that are late to the party) seem to think it’s just “a cool syntax” and little more.

    BDD is just TDD made easier to do well.

    Actually, that’s not entirely true. There is also another dimension of BDD, which is about User Stories and Acceptance Criteria. BDD also provides a language framework for how they can be written (or spoken) in a way that makes it easier to translate them to code. This ties into the idea of Domain Driven Design and the whole Ubiqutous Language thing. I’ll write about that some other day – there isn’t much available out there on this topic, at least not in a way that brings it all together.

  4. NeologistDecember 12, 2006 @ 12:36 AM

    Testing is not a past tense activity.

    It’s only a past tense activity if you are used to only testing things that happened in the past.

    Many people test for things that they do not yet know exist (e.g. scientists, oil explorers).

    The problem is not the word “test”. It’s the overly narrow interpretation of what “test” means in a software context. How does BDD help? By just ignoring the issue altogether and creating a new incorrect interpretation of the word “behaviour”?

  5. David ChelimskyDecember 13, 2006 @ 10:39 PM

    Neologist – it helps at the very least by promoting this very conversation. How does it hurt?

  6. NeologistDecember 14, 2006 @ 06:42 AM

    It hurst by

    a) misrepresenting what TDD is and therefore confusing the whole discussion about it and making it harder to talk about, sell into organisations and skill up development teams

    b) misrepresenting what “behaviour” is, so making it harder to actually talk about object-oriented software and design

    c) misusing existing terminology of specification, so making communication between people who know about software specification and those who only know about BDD difficult

    d) introducing new, unnecessary, inconsistent and inexact terminology, so making it harder to talk about software design and development process

  7. topfunkyDecember 14, 2006 @ 11:14 AM

    I think some of these alternate implementations are the result of the decision to make RSpec an all-or-nothing proposition. People want to learn BDD, but also have existing projects with extensive test suites.

    Maybe we need to see a blog post where test::unit and rspec co-exist?

  8. David ChelimskyDecember 16, 2006 @ 07:48 AM

    Neologist:

    a) “misrepresenting what TDD is”???? How so?

    b) “misrepresenting what \”behaviour\” is” – I see in your earlier comment that you see behaviour as being driven by the tests, rather than behaviour. Is that how you see behaviour as being misrepresented?

    c) Agreed. RSpec is an unfortunate choice of names.

    d) Agreed in part.

    So what would you suggest we do from here?

  9. David ChelimskyDecember 16, 2006 @ 07:54 AM

    Neologist – “That IS test-driven development. If you don’t write your tests that way you’re doing testing but your tests aren’t actually driving anything.”

    I think that’s a major reason why BDD exists. Because you CAN, in fact, drive the code from tests that are all about the internal structure of an object – and many people do.

    “BDD is a cargo cult, maybe. But it’s certainly just rebranding something that already has a perfectly good name with a new, meaningless terminology.

    If you think that RSpec IS BDD, then you are correct. However, BDD is quite a bit more than just RSpec. You should give http://dannorth.net/ a read to get a better handle on the bigger picture. You may not like it any more than you do now, but at least you’ll see where it’s coming from, which is not RSpec. RSpec is a means, not an end.

  10. Pat MaddoxDecember 18, 2006 @ 10:43 AM

    One thing I’ve learned from BDD (or at least using RSpec) is that I have to have high-level acceptance tests. In the past I did the standard “TDD” “call a method and then check some values.” My code worked pretty well and was easy to refactor, but it wasn’t particularly well-designed. It certainly wasn’t good OOP.

    Since moving to RSpec, I’ve started using mock objects more. I’ve found that using mock objects can make it a lot tougher to refactor. Refactoring basically always changes the internal behavior of the system, requiring me to change my specs. Not only is it a bit annoying, but you don’t have the same confidence as refactoring your state-based-tested code, where the tests won’t need to change.

    Of course you more experienced programmers will say that I should be writing acceptance tests anyway. For me though, my projects have been small enough that as long as it’s unit-tested it’s okay. That’s no longer the case, but I think I’m okay with that. My specifications document how I can use my code. Acceptance tests allow me to refactor the specs and code to make sure that I haven’t broken the observable behavior of the system.

    Is it safe to say that acceptance tests can be state-based, for the most part? You don’t particularly care about what’s going on inside the system, but rather that the system is in a particular state after performing some particular action.