Highly Opinionated Thoughts on Programming

by Elnur Abdurrakhimov


Use the Domain Language in BDD Features

Nov 24, 2013


I see this so often that it seems like there’s some global confusion on what features should look like. Here is an example of a feature done wrong:

 1 Feature: Discounts for customers  
 2   In order to be more motivated to buy more stuff in this shop
 3   As a customer
 4   I want to get discounts when I buy lots of stuff
 5 
 6   Scenario: Provide a $10 discount when buying goods for more than $100
 7     Given I'm a customer
 8     And category "Pure Awesomeness" exists
 9     And product "Super Awesome Stuff" exists
10     And product "Super Awesome Stuff" is in the "Pure Awesomeness" category
11     And product "Super Awesome Stuff" costs $30
12     And I'm on the homepage
13     When I go to the "Pure Awesomeness" category page
14     And I click "Super Awesome Stuff"
15     And I click "Add to Cart"
16     And I fill "Amount" with 10
17     And I click "OK"
18     Then I should see "Subtotal" is "$300"
19     And I should see "Discount" is "$10"
20     And I should see "Total" is "$290"

To most developers out there it seems perfectly okay. So why do I think it’s wrong? Let’s go with this step by step.

First, it’s hard to read the whole scenario in one go without losing focus. What’s actually being specified here: discounting or UI? It’s supposed to specify the discounting logic, but it’s hard to see that right away because of all the UI noise.

And what happens when you add another type of UI — like GUI or RESTful API — to your application? Will you duplicate the same feature for each type of UI you have? That doesn’t make sense. It makes more sense to specify the domain logic once and have separate specifications or tests for each type of UI separately.

I’m not saying there’s no place for UI specifications in BDD. There is, but they should be separated from the domain logic ones. If your stakeholders really want to keep the contorl of UI in their hands, it’s okay to have separate UI specifications. But if they’re not, you could use other tools for UI testing — something without the overhead of text-to-code translation.

So, let’s go and remove the UI stuff from the scenario:

 1 Scenario: Provide a $10 discount when buying goods for more than $100  
 2   Given I'm a customer
 3   And category "Pure Awesomeness" exists
 4   And product "Super Awesome Stuff" exists
 5   And product "Super Awesome Stuff" is in the "Pure Awesomeness" category
 6   And product "Super Awesome Stuff" costs $30
 7   When I add 10 units of "Super Awesome Stuff" to the cart
 8   Then the subtotal should be $300
 9   And the discount should be $10
10   And the total should be $290

It’s shorter and less noisy now, but it hasn’t lost anything important. This is a step in the right direction. This scenario is not tied to a particular type of UI and will still make sense no matter how many types of UI you’ll have eventually. It still makes sense even if there’s no UI at all. That can be the case if you’re developing a library to be used in other applications with their own UIs.

Okay. Let’s go further. Does it really matter which category the product is in? The discounting logic in this case doesn’t depend on categories, so they’re an example of incidental details that add to the noise. Let’s remove them:

1 Scenario: Provide a $10 discount when buying goods for more than $100  
2   Given I'm a customer
3   And product "Super Awesome Stuff" exists
4   And product "Super Awesome Stuff" costs $30
5   When I add 10 units of "Super Awesome Stuff" to the cart
6   Then the subtotal should be $300
7   And the discount should be $10
8   And the total should be $290

Now it’s even less cluttered and closer to the point. But we can go further. The next question is: does it really matter which product and amount of it I add to the cart? It doesn’t because only the total cost of the cart contents is what matters here. Let’s remove that too:

1 Scenario: Provide a $10 discount when buying goods for more than $100  
2   Given I'm a customer
3   When I add $300 worth of products to the cart
4   Then the subtotal should be $300
5   And the discount should be $10
6   And the total should be $290

Now it’s even shorter and still hasn’t lost anything important. But it can be improved even more. Do we need all that subtotal-discount-total stuff? No. At least, it doesn’t matter for this scenario. If it’s important to specify that stuff, it can be done in a separate feature dedicated to that. So, let’s remove that too:

1 Scenario: Provide a $10 discount when buying goods for more than $100  
2   Given I'm a customer
3   When I add $300 worth of products to the cart
4   Then the total should be $290

Much better. Now we can really tell what this scenario is about. We’ve removed all the noise but everything important is still there. There’s nothing left to remove without losing the point of the scenario. That’s the goal: remove everything you can without losing the point.



© Elnur Abdurrakhimov