Last week I went to the 2bd SoCraTes conference, the German Software Craftsmanship and Testing conference. We did two days of open space discussions, and we all had great fun. One thing though that caused me some extensive amount of trouble, was the amount of sessions around BDD.
Some time ago, I wrote about the given/when/then-fallacy. But this time was different. Despite the amount of emphasize that BDD puts on the ubiquitous language, I was shrugged by the fact that folks were pointing to different things while talking about BDD: It seems BDD suffers from the same thing that it tries to prevent: having a common understanding about stuff.
I don’t know where this particularly comes from, and I also saw a couple of bad scenarios when it comes to the usage of tools like Cucumber or JBehave. I don’t consider myself a BDD expert, and people pointed out that I do something different around acceptance tests. Still I thought to expose some of my thoughts about some of the examples that I ran across recently – and helped out improving. Here’s my though process on two of these scenarios.
The first example I crossed while reviewing some sessions for the XP Days Germany later this year. I offered some help with improving it. Here is the original version of a scenario:
Given a recorded customer X
Given an existing product Y
and its availability should be two
When X orders Y once
Then expect a remaining availability of Y of one
Now, I see several things that could help make this scenario more independent from the particular (current) implementation. The first line appears to me to be there just for technical reasons. So let’s try to drop it. The second and the third line actually set up the context together. I think we should try to combine them. Such a combination could work like the follwoing:
Given a product Y that is available “2” time(s) in stock
Now, we have the direct connection between the product and the availability. That should do it for the time being.
The fourth line is a bit troublesome to me. It seems to be hard to reuse it later, if we happen to decide to go for ordering multiple items of product Y. Anyways, we wanted to include the customer in there. How about this:
When a customer orders product Y “1” time(s)
A bit better. In particular, I don’t like the “time(s)” reference, but would go for that for the time being.
The final line suffers from a similar problem as the fourth line. Let’s try to remove that problem there as well, maybe trying to reference the given context we identified earlier. Here’s a first throw:
Then the product Y remains in stock “1” time(s)
Sort of ok. Let’s put the three together:
Given a product Y that is available “2” time(s) in stock
When a customer orders the product Y “1” time(s)
Then the product Y remains in stock “1” time(s)
This could be a good starting time. Maybe we need to give it some more thought. That would depend from my part on how often we are going to reuse which part, and what is likely to change in the next few weeks, and what is unlikely to change. Notice that most of the technically coupled details from the original scenario are still there, and I pushed that down one more level to the concrete implementation of the step-definitions. And now we won’t need to change all tests because we cluttered the example descriptions with it. Instead we will need to change the step definitions in case we change something to that binding.
I often fail at identifying the proper binding, and I try to learn from it each time I do. There is still coupling between the examples and the product implementation, though, and I hope that I picked the right trade-off decision here. I can’t know it, but it seems to be my best option so far. Maybe that is why I don’t try to automate everything, but tackle the more interesting pieces with more easy to maintain tests run by hand – maybe supported by the automation that is already there.
Passive scenarios
A second problem I see a lot in scenarios has to do with passiveness. Most writers (in English and German, at least to my experience) know that passive writing is boring, and usually it is edited out by copy-editors (just like the last part of this sentence would have been). In terms of scenarios this seems to happen a lot once the word “I” is used – leaving the future reader of that scenario unaware of who that I is.
Here is a second scenario I saw on the flip charts at SoCraTes:
Given I have started my day
When I open the Sales App
And I want to tweet my location
Then my location is available on twitter for my customers
Notice that you don’t have a clue who started his day. Notice the amount of effort it takes you to follow that scenario without it. The person in question is mentioned in the user story above. It’s a hot dog seller scenario. Without mentioning it, you can actually replace that. So, what let’s try to make the whole thing more active:
Given a hot dog seller
When he tweets his location at location Bielefeld, Germany
Then his customers will see Bielefeld, Germany as his location
Now, the actor is clear. It’s way harder to take this scenario out of its meaningful context in the way I formulated it. And there is still something that troubles me. But I will leave this to the interested reader to tear out. Thereby I hope to expose the power of collaboration on the scenarios.
Don’t overestimate BDD
I was a bit peeved the other while listening to a rant about agile people testing, and just focusing on BDD in that. Maybe I was just made aware of the problem. With about five sessions in the SoCraTes open space on the topic, yet no programmer really agreeing on what that term actually means, made me suspicious. If anything at all, you should make take BDD as a tool, using it when it’s appropriate, and don’t overuse it, or even overestimate its benefit. You will still leave gaps of things you didn’t consider. Maybe put more emphasize on the polimorphic actions that are hard to automate. Oh, and you can’t do that with Cucumber or JBehave.
I have to admit that lazyness led me to unwell crafted example specifications, but their usefullness was not important to get an idea of what event centric testing can do.
You got one thing wrong I think.
The first line “Given a customer X has been recorded” is not merely there for technical reasons. In an event sourced application we can test the whole domain as black box, just by setting the history with a series of events, written in prose. The same events that the domainobjects use to get into their actual state. So when we say
“Give [a series of events]
When [a command is executed]
Then expect [a series of events]”
Then we need the whole history that sets our domain in a valid state… including the recorded customers ;)
Thanks for your great help with words though, as always greatly appreciated.
Have a nice code,
Marco Heimeshoff
Polimorphic actions are not hard to automate. Polimorphic actions are, by definition, impossible to automate. Mimeomorphic actions may or may not be automated, but are at least in theory automatable.
—Michael B.