~ $ cd craft/a-sentence-is-a-step && cat README.md
A sentence is a step,
named by its own words.
A behaviour test written in plain sentences needs, for every sentence, a piece of code that knows what to do with it, and the usual way to find that piece is a pattern — a regular expression, or a Cucumber expression — written to match the sentence. That is where my students got stuck: on the expressions, and on naming the functions behind the steps.
So the course's platform stopped matching sentences, and read them instead. Every word goes into the name of a method; a quoted string becomes an argument and an S in the name, a number an argument and an N. There is nothing to match, because the sentence is the name. In that course the post came first and was the test, and each of its sentences a step: write one, a step a line, and see what it becomes:
* Go to the blog section, * You should see a list of posts, * The last post title should be "Hello Blog", this post
The test, for the server
@Test
public void post() {
context.goToTheBlogSection(); // Go to the blog section,
context.youShouldSeeAListOfPosts(); // You should see a list of posts,
context.theLastPostTitleShouldBeSThisPost("Hello Blog"); // The last post title should be "Hello Blog", this post
}The test, for the client
test("post", () => {
context.goToTheBlogSection(); // Go to the blog section,
context.youShouldSeeAListOfPosts(); // You should see a list of posts,
context.theLastPostTitleShouldBeSThisPost("Hello Blog"); // The last post title should be "Hello Blog", this post
});What is left to write, in Java
public void goToTheBlogSection() {
// to write
}
public void youShouldSeeAListOfPosts() {
// to write
}
public void theLastPostTitleShouldBeSThisPost(String expected) {
// to write
}And in JavaScript
goToTheBlogSection() {
// to write
}
youShouldSeeAListOfPosts() {
// to write
}
theLastPostTitleShouldBeSThisPost(expected) {
// to write
}The test is the same for the server and for the client, one call a step, with the step's sentence beside it — so a line that fails says, in the student's own words, what did not happen. What is left to write are the methods at the bottom, and writing them is the work. The rest of that course is in its own page.
Where it went
The idea went through several versions in the course, and then out of it, as Gherkin Genie: the same reading of sentences, for Gherkin and for any test runner, with no regular expressions at all. A missing step is printed as the method to paste in, already named. Later it was adapted once more, for the tests of a product at work.
Here it is with the example of its own README: a feature about cucumbers, and the steps with one method written. Genie prints the two still missing; paste them into the steps, fill them in, and the scenario runs.
Feature: Magic of Disappearing Cucumbers
Scenario: Eating 5 out of 12 cucumbers
Given I have 12 cucumbers
When I eat 5 cucumbers
Then I should have 7 cucumbers remainingclass CucumberSteps {
#count = 0;
givenIHaveNCucumbers(count) {
this.#count = count;
}
}There are missing steps. Please implement them:
class WishedSteps {
whenIEatNCucumbers(number1) {
throw new Error("Unimplemented");
}
thenIShouldHaveNCucumbersRemaining(number1) {
throw new Error("Unimplemented");
}
}Genie reads a feature with Cucumber's own parser; the page reads a part of Gherkin — scenarios, a background, steps, tables and doc strings — with a few lines of its own, and names each step by Genie's own rules.