söndag 6 februari 2022

Gherkin - det gemensamma "språket" från produktägare till utvecklare

Gherkin

Jag har nu haft möjligheten att använda Gherkin på jobbet, ett språk, eller kanske mer en mall, som används för att skriva systemtest så att de ska bli läsbara och förståeliga hela vägen från produktägare till utvecklare. Vi är bara i början av resan, men det verkar mycket lovande och intressant! Rekommenderar!

Om du är som jag och undrar varför saker heter som de heter så kan jag avslöja att gherkin betyder "liten picklad gurka". Och språket Gherkin används i testramverket Cucumber, vilket frun till skaparen fick namnge:

My wife suggested I call it Cucumber (for no particular reason), so that's how it got its name. I also decided to give the Given-When-Then syntax a name, to separate it from the tool. That's why it's called Gherkin (a small, pickled Cucumber).


Cucumber är ett Ruby-ramverk, sitter du med .net så är det SpecFlow som gäller om du vill skriva test med Gherkin.

För att du ska få en känsla för hur språket ser ut så kommer här ett exempel, där de fetkursiva orden, samt möjligheten till den korta beskrivningen på raden under scenario, tillhör Gherkin:

Scenario: Duplicate email

Where someone tries to create an account for an email address that already exists.

Given I have chosen to sign up

But I enter an email address that has already registered

Then I should be told that the email is already registered

And I should be offered the option to recover my password


plant, fruit, food, green, produce, vegetable, fresh, kitchen, gourd, eating, vegetables, cucumber, cucurbita, cucumbers, gherkin, preparations, flowering plant, pickled cucumber, ensiling cucumbers, mizeria, land plant, cucumber gourd and melon family, summer squash, Free Images In PxHere


Godbitar jag hittat

För att komma in i testskrivandet lite snabbare så läste jag The Cucumber Book - Behaviour-Driven Development for Testers and Developers. Här nedan kommer de partier jag markerat som "kom ihåg" under läsning.




Readability

When you're writing Cucumber features, make readability your main goal. Otherwise, a reader can easily feel more like they're reading a computer program than a specification document, which is something we want you to try to avoid at all costs. After all, if your features aren't easy for nonprogrammers to read, you might as well just be writing your tests in plain old Ruby code. The real key to expressive scenarios is having a healthy vocabulary of domain language to use to express your requirements. That said, using only the basic set of Gherkin keywords can often make your features repetitive, making them cluttered and awkward to read. By the end of this chapter you'll know everything there is to know about Gherkin's syntax, giving you all the tools you need to write clear, readable Cubumber acceptance tests.

System tests Vs unit tests

It's also worth thinking about whether some of the behavior you've specified in Cucumber scenarios could be pushed down and expressed in fast unit tests instead. Teams that enthusiastically embrace Cucumber sometimes forget to write unit tests as well and rely too much on slow integration tests for feedback. Try to think of your Cucumber scenarios as broad brush strokes that communicate the general behavior of the code to the business, but still try to get as good a coverage as you can from fast unit tests. Help make this happen by having testers and programmers work in pairs when implementing Cucumber scenarios. This pair can make good decisions about whether a piece of behavior necessarily needs to be implemented in a slow end-to-end Cucumber scenario and drive out the behavior using a fast unit test instead.

Överflödiga detaljer

Nedanstående test tas upp som ett exempel på ett test som innehåller alldeles för mycket detaljer på fel nivå.

Ett scenario för en e-postklient på webben:

Scenario: Check inbox
Given a User "Dave" with password "password"
And a User "Sue" with password "secret"
And an email to "Dave" from "Sue"
When I sign in as "Dave" with password "password"
Then I should see 1 email from "Sue" in my inbox

Användarnamnen är användbara, eftersom de är viktiga beståndsdelar i scenariot, men lösenorden är bara brus, de har inget att göra med det som testas och gör testet svårare att läsa. Till exempel så har Sue ett annat lösenord än Dave, vilket kan leda till att du som läsare av testet börjar fundera över om den delen är relevant och tappar då fokus från scenariots huvudsakliga mening, dvs: att testa att Dave kan se Sues email.

Lösenorden är alltså överflödiga detaljer (incidental details), detaljer som nämns i scenariot, men som saknar relevans för scenariots uppgift. 

Här är testet utan lösenord:

Scenario: Check inbox
Given a User "Dave"
And a User "Sue"
And an email to "Dave" from "Sue"
When I sign in as "Dave"
Then I should see 1 email from "Sue" in my inbox

En klar förbättring, mer lättläst och testets betydelse framträder tydligare. Ännu mer brus kan tas bort:

Scenario: Check inbox
Given I have received an email from "Sue"
When I sign in
Then I should see 1 email from "Sue" in my inbox

Nu är det ett koncist trestegs-scenario, som också är lättare att underhålla. Om användarautentiseringen måste ändras, så påverkar det inte själva testet utan bara koden bakom. 

When Cucumbers Go Bad: Imperative Steps

In computer programming, there are two contrasting styles for expressing the instructions you give to a computer to make it do something for you. These styles are called imperative programming and declarative programming.

Imperative programming means using a sequence of commands for the computer to perform in a particular order. Ruby is an example of an imperative language: you write a program as a series of statements that Ruby runs one at a time. 
A declarative program tells the computer what it should do without prescribing precisely how to do it. CSS is an example of a declarative language: you tell the computer what the various elements on a web page should look like, and you leave it to take care of the rest.

Exempel i imperativ stil:

Scenario: Redirect user to originally requested page after logging in
Given a User "dave" exists with password "secret"
And I am not logged in
When I navigate to the home page
Then I am redirected to the login form
When I fill in "Username" with "dave"
And I fill in "Password" with "secret"
And I press "Login"
Then I should be on the home page

Enligt författaren så kan man argumentera att ovanstående testexempel har en del fördelar. Men han menar på att man snart kommer drabbas av problem med test som lätt går sönder och uttråkade intressenter, t ex produktägaren. Test som skrivs på den stilen blir brusiga, långa, tråkiga att läsa och går lätt sönder. Till exempel en så liten ändring som en omdöpning av knappen från "Login" till "Log in" får testet att gå sönder.

Men det värsta är att språket inte tillhör den egentliga problemdomänen, utan blir mer lågnivå-språk med ord som "fill in" och "press", vilka tillhör gui-domänen.

Exemplet i deklarativ stil:

Scenario: Redirect user to originally requested page after logging in
Given I am an unauthenticated User
When I attempt to view som restriced content
Then I am shown a login form
When I authenticate with valid credentials
Then I should be shown the restricted content

Författaren skriver att det snygga med detta är att testet inte kopplas till en specifik implementation av användargränssnittet. Samma scenario kan användas för en desktop-app som en mobil-app.
Orden som används (unauthenticated, restricted, credentials) är förståeliga för en intressent som håller på med säkerhet.

It's true that using declarative style will mean you have to write more step definitions, but you can keep the code in those step definitions short and easy to maintain by pushing the actual work off into helper methods in your support code.