Highly Opinionated Thoughts on Programming

by Elnur Abdurrakhimov

BDD Does Not Replace Testing

Apr 23, 2014

It seems that the biggest reason for BDD done wrong is the notion that BDD is a new shiny form of TDD and thus one completely replaces the other. They completely abandon technical tests and start using BDD for everything. No wonder it fails and they go complaining that BDD sucks and then switch completely back from BDD to technical tests.

BDD Solves Communication Problems

BDD was invented to solve communication problems between business and technical people. The root of those problems is that people understand the same word or phrase differently. That usually leads to wrong software being built.

With BDD you specify details in the form of examples and that eliminates most if not all of misunderstanding and miscommunication.

Regression testing is just a byproduct of BDD; it’s not the goal. The goal is to eliminate misunderstanding of what to build before you start building it.

If you’re the only developer working on your own project, you probably don’t need BDD at all. If you have a communication problem with yourself, you have a bigger problem and BDD will not help you.

Testing Solves Technical Problems

There are lots of forms of tests. On one project I usually have at least 3 types of technical tests: unit, integration, and UI/API tests.

I write unit tests to either drive design of nontrivial object interaction or test nontrivial methods doing calculations of some sort. I don’t write unit tests for getters and setters or other trivial code because those parts of code will be covered by higher level tests anyway.

I write integrational tests for pieces of code that can’t be reliably tested with unit tests: validation, repositores, etc.

I write UI/API tests to test that everything works end-to-end. Tests of this kind go through complete vertical slices down to the DB.

When I need to test an aspect of an application, I write the most low level test I can to reliably test a piece of code to keep the tests execution time as low as possible without sacrificing the confidence in tests. That means that if I can test something with a unit test, I will write a unit test. The same thing could be tested with an integrational or UI/API test but that would take more time.

So, for instance, if I need to test validation rules, I write an integration test for that and then write another UI/API test to make sure that when a validation rule is violated, the right error message shows up and nothing gets persisted to the DB. I don’t test all the combinations of validation rules with UI/API tests because that would complicate tests and make them slow. Instead I test all the validation combinations with integration tests.

One Does Not Replace Another

Most of the time, BDD specifications involve domain only and run directly against domain code. By domain I don’t mean just unit level objects; a DB might be involved here as well. But BDD should rarely if ever involve UI/API. I’d say that BDD should operate on the same level as integration tests do.

Technical tests, on the other hand, cover everything else, including some parts of the domain if those are too trivial to specify in BDD specifications. For example, you might want to write a unit test to be sure that age calculation based on birthdate works correctly, while specifying this in the form of BDD specifications would be an overkill because I doubt there is a way to miscommunicate on a calculation like this.

All in all, BDD helps to build the right product; TDD helps to build the product right.


© Elnur Abdurrakhimov