If you’re non-technical and have worked with web or mobile engineers to build or modify a product at some point in time, or would like to in the future, then this post is for you. While you may be calling the shots for an engineering product or feature, the more removed from the development process you are, the less influence and insight you actually have. Given this reality, it is paramount that you explicitly define the product in a very specific way before any development begins. My goal here is to empower you to collaborate with engineers in a way that guarantees your vision by writing executable test cases that define your expectations.
Let’s say your non-technical department at an architecture firm wants to build an application that calculates the third side of right triangles (among other things). You want your company’s engineering team to build this tool for you. Ideally it would be a web application so that your employees in the field can perform calculations wherever they are. For our purposes, let’s say the program runs on employee computers instead of a web application.
If you go to the engineering department and request this feature, the team would ask you for some specifications, then translate your vision into a tangible product. In a perfect world, your ideas for the application perfectly match theirs right off the bat. Yet, this is rarely the case. While inefficient, back and forth communication can usually iron out most misunderstandings. Nevertheless, unless you approach the feature requirements from a comprehensive user perspective, the team has to make several assumptions — that impact product scope, behavior, and timeline — during development. This can set the stage for missed deadlines and bugs (errors) in the code.
Instead of outlining specifications like “enter two numbers and get the third side of the triangle,” send over a complete set of user-based scenarios with preconditions, user interactions, and expected results for the feature that doubles as a list of executable automated tests that validate your requirements. Your guidelines will be preserved and obeyed for the lifespan of the product; not left on a desk under a pile of other engineering requests or deep within an email inbox. Moreover, by breaking a feature down into requirements, you’ll understand how complex it actually is and (hopefully) set realistic deadlines [ after discussing timeframe with your engineers ].
If you’re on a mac: Select the finder search bar in the top right hand corner of your screen. Type in textedit. Click on the textedit item in the list to open the application. Select format > Make Plain Text or SHIFT + APPLE + T. This final step is important because other formats will add extra characters to your text file that prevent it from running properly when you hand it off to developers.
If you’re on a PC: Open notepad. It can usually be found under accessories from the start menu.
As a side note, using a shell is ideal for what I’m about to show, but I’m afraid the complexity it introduces will only act as a barrier for someone with no previous shell interaction. As a non-technical person collaborating with engineers, everything you’ll want to hand off to an engineering team can be done with a simple text editor. Leave the other parts to them, but more on that later.
Save your text file as pythagorean.feature, since the engineers will most likely use the pythagorean theorem as their mathematical model.
This .feature file can be read by a ruby Behavior Driven Development (BDD) test tool known as Cucumber. Before any feature or product development begins, scope out your expectations for the feature in a .feature file. If you have more than one feature request, add a .feature file for each. You can then hand this to your engineering team so that they can develop against it. I say against because they’ll write code that allows each one of your Cucumber expectations to pass.
Here’s a link to the root of the Pythagorean demo I’ve created: https://github.com/acockell/confidentqa/tree/master/features.
Here’s a link to the .feature file you would write for our pythagorean theorem feature: https://github.com/acockell/confidentqa/blob/master/features/pythagorean.feature.
Start the .feature file with the Feature keyword followed by the feature title. I’ve named the feature Pythagorean Calculator.
Feature: Pythagorean Calculator
Next, add an “In order to” description for the feature right below the title. You’ll want this because if you can’t justify your feature then it’s probably not adding value to the business. Find more on that here: https://github.com/cucumber/cucumber/wiki.
In order to find the third side of a right triangle As someone who is too smart to perform a calculation every time I want to be told the missing side of the triangle if I give two sides
In our case, I want to build the feature to find the third side of a right triangle because I know I’ll have to perform this calculation often and want to make it easier for myself and my colleagues. For Behavior Driven Development, place yourself in the shoes of your user and write everything in the .feature file from that point of view.
Next, write scenarios starting with the Scenario keyword. Each scenario is a requirement of the feature you want. These convert into executable tests. Our first requirement is that we want the hypotenuse to be returned by the program.
Scenario: Return the hypotenuse (a + b)
Below each scenario title, describe the scenario in more detail using Given, When, and Then. The Given keyword denotes a precondition. A precondition for using our calculator could be something as simple as starting the calculator. The When keyword denotes a user action. Our user would most likely enter a number for each side into the calculator. Our user would also request the final value. The Then keyword denotes the outcome. Our user would expect to see a value after entering two sides and requesting the third side.
Given I have started the calculator When I have entered 5 into the calculator first When I have entered 12 into the calculator second When I request the hypotenuse Then I should see 13.0 as the final value
Each feature should include an exhaustive list of scenarios like the one above, where each Scenario “block” is separated with a new line. You’ll want to write scenarios for every valid and invalid user scenario you can imagine. In an invalid scenario, for example, the user would input one or more negative numbers (or zero) for each side; we all know that a triangle is composed of positive sides. In this scenario, we need to alert the user that this is impossible. Define an expectation like “the value returned should be -1,” for example. As we cover more valid and invalid user interactions in the text file, we reduce the likelihood of bugs in the final product. We also inadvertently communicate the scope or depth of the project.
To make the feature requirements easier to read, there’s a few moves we can make. Instead of writing the same Given(s) for each scenario over and over, we can move the Given precondition(s) we use throughout the feature to a background block right below our feature description.
Background Given I have started the calculator
We can also use the And keyword when there is more than one Given, When, or Then inside of a scenario block. Here’s an updated version of our first scenario:
Scenario: Return the hypotenuse (a + b) And I have entered 5 into the calculator first And I have entered 12 into the calculator second When I request the hypotenuse Then I should see 13.0 as the final value
Also, take note of the spacing. Each scenario should use either a space or indentation. Everything within that should use two.
As the number of requirements starts to add up, and you want to ensure that your feature covers edge cases like negative numbers, the above may start to get overwhelming. Even though it feels like a text document, you’re actually working with a smart programming language known as Gherkin. Let’s say you want the developer’s work to return the right values for 3-4-5 triangles, 8-15-17 triangles, etc. There’s no need to write a scenario for each of these specific values. You can write a single scenario that pulls numbers from a table and plugs them into the scenario when it runs in Cucumber. In the scenario, include each table column name inside a tag, change the Scenario keyword to Scenario Outline, and create a table directly below the scenario with the Examples keyword.
Scenario Outline: Return the hypotenuse And I have entered into the calculator first And I have entered into the calculator second When I request the hypotenuse Then I should see as the final value Examples: | first | second | value | | 3 | 4 | 5.0 | | 8 | 15 | 17.0 | | 20 | 21 | 29.0 | | 33 | 56 | 65.0 | | 36 | 77 | 85.0 |
When a developer runs Cucumber (with the `cucumber features` command in a shell), the scenarios from your feature will run [ assuming they have the ruby gem for Cucumber – they should know how to get this ].
19 scenarios (19 undefined) 76 steps (76 undefined) 0m0.051s
All scenarios and steps will be undefined. It is the engineer’s job to build the feature and define steps that make each pass during development. When all scenarios pass for your feature, all of your requirements have been met by the developer. The process of writing code to make tests pass is referred to as Test Driven Development (TDD), and it started with you. A final feature will resemble the output below:
19 scenarios (19 passed) 76 steps (76 passed) 0m0.039s
As a side note, notice how you can validate all of your requirements for a feature in less than .1 seconds.
If your engineering team is worried that this will add too much work on their end, here are the step definitions that I wrote to make all of the scenarios pass:
Given /I have started the calculator/ do # @right_triangle = Pythagorean.new end Given /I have entered (.*) into the calculator first/ do |value| @right_triangle.side_one value end Given /I have entered (.*) into the calculator second/ do |value| @right_triangle.side_two value end When /I request the hypotenuse/ do @right_triangle.hypotenuse end When /I request the third side/ do @right_triangle.side end Then /I should see (.*) as the final value/ do |value| expect(@right_triangle.final.to_s).to eq(value) end
While I don’t expect everyone to understand what is posted above, the takeaway is that my actual .feature file is where most of the effort and energy went. By defining features in a format that can be plugged into a Cucumber project, we not only give our developers a concrete list of expectations, but also provide them with executable tests.
On a related note, write lines that are organizationally similar, when possible, to save developers time. Don’t do this:
Scenario: Return the hypotenuse (a + b) And I have entered 5 into the calculator first And I have entered 12 into the calculator second When I request the hypotenuse Then I should see 13.0 as the final value Scenario: Return a side other than the hypotenuse (a + c) And I have entered 5 into the calculator the first time And I have entered 13 into the calculator second When I request the third side Then the final value returned should be 12.0
In the above example, the developer would have to write a case for “And I have entered 5 into the calculator first” as well as “And I have entered 5 into the calculator the first time.” The same problem arises for “Then I should see 13.0 as the final value” and “Then the final value returned should be 12.0.”
On the other hand, numbers, letters, and words in a fill-in-the-blank syntax are fair game: “Then I should see ___ as the final value.” You could write “Then I should see fifteen as the final value” and “Then I should see 100 as the final value,” and the developer would only need one case to cover both.
My pythagorean calculator is nothing more than a silly ruby file, but this concept can be used for larger web projects with hundreds of files. Moreover, your engineering team can choose the appropriate test tool that Cucumber leverages to test; while I did not utilize a browser driver for my test, as my project was a ruby file instead of a web project, there are automation tools (Watir, Selenium, and Capybara) compatible with Cucumber that engineers can use to validate web page interaction. With tools like that, you could define Cucumber expectations that require interaction with a web page.
Scenario: Submit Registration Form Given I am on the registration page When I enter Adam as my name And press the submit button Then my account should be created And I should see a Welcome Adam message on the confirmation page
Cucumber is pretty cool. There are certainly arguments against it, but for bridging the gap between the technical and non-technical, it is a game changer with very little additional effort on the engineering side.
If your engineers need any reference or getting started help for their end of the deal, they can check my repository ( https://github.com/acockell/confidentqa_cucumber ) or the Cucumber wiki ( https://github.com/cucumber/cucumber/wiki ).