How and why I test

04 December 2019

When I got into automated testing

I remember quite vividly the moment I got started with testing. It was the winter of 2012 and I was freelancing for the company Zilverline.

I started quite early in the morning

Before this day in December, I tested how most people tested back then (and maybe still today)—manually, by repeating scenarios. So while I was working on a project I was just clicking through the website and seeing if anything was broken.

While this is a great way to test software, there are other ways that give you more certainty that everything is working.

Why do we test?

The first question you should ask is why would I write an automated test? For me, the easiest answer is one word: “confidence.” Without tests, I cannot have confidence that my software works as designed. When you start adding automated tests you gain confidence that the software works as expected. This allows you to deploy automatically after each change (also known as “continuous deployment”).

What does a test look like?

Tests can also be viewed as a way to record a certain behavior of the software. I will illustrate this with a real-world example.

Test one thing a time

In this example, I want to test that the website knows how to handle a certain state.

For this example, I’m using Ruby RSpec because of its readability.

it "shows a message when there are no invites available" do
  sign_in create(:user)

  visit invites_path

  expect(page).to have_content "No invites available"
end

As you can see, I’m only testing one thing at a time. I’ll try to make the test as narrow as possible so it won’t break when there is something wrong on the other side of the application.

The four phases of testing

There are four phases in a test as you see in the example above. These phases could have a new line between them for readability.

Make tests even more readable with Gherkin 🥒

In the example above, you saw the testing language RSpec, which has a readable syntax. However, if you want to take it one step further in terms of readability, then you could go for the Gherkin language.

Below you see a simple example of a test:

Feature: Sign in
  I want to see the sign in page

  Scenario: Shows an error with wrong password
    Given I visit the homepage
    When I sign in with wrong password
    Then I should see that the credentials are wrong

It even has more advanced features like Scenario Outlines:

Scenario Outline: eating
  Given there are <start> cucumbers
  When I eat <eat> cucumbers
  Then I should have <left> cucumbers

  Examples:
    | start | eat | left |
    |    12 |   5 |    7 |
    |    20 |   5 |   15 |

TDD is dead. Long live testing.

David Heinemeier Hansson has some great points in his article with the provocative title “TDD is dead”:

The current fanatical TDD experience leads to a primary focus on the unit tests, because those are the tests capable of driving the code design (the original justification for test-first).

I don’t think that’s healthy. Test-first units leads to an overly complex web of intermediary objects and indirection in order to avoid doing anything that’s “slow”. Like hitting the database. Or file IO. Or going through the browser to test the whole system. It’s given birth to some truly horrendous monstrosities of architecture. A dense jungle of service objects, command patterns, and worse.

When I started testing, I also first focussed on the tests. And then I started implementing the code. After seeing David’s talk at Rails Conf, I realized that testing first isn’t always the best way to write code.

I started to look at ways to do full-stack front-end testing and about a year ago I ran into Cypress.

With Cypress, you can control a browser that interacts with your project. It provides a really powerful API so everything you can do in a browser is available.

In the project for Close, I’m using Gherkin to write tests against Chrome. After you run the test, you get a video of the test that looks like this: