Registration - Part 3 - Unhappy Paths


If we lived in a perfect world, we would now be done with our User Registation workflow. In the previous video we covered the "happy path" journey for a user to successfully register when providing good details.

In the real world, however, things often go awry.

Whether a user has provided an invalid email, or messed up their password / confirmation password, we need to check that our system behaves as expected when bad input is provided.

To do this we also need to check the "unhappy paths" through our code. These are the paths that are expected to happen, and that our system should reject but with graceful / helpful feedback.

Let's look at the extra scenarios:

# /src/AppBundle/Features/register.feature

Feature: Handle user registration via the RESTful API

  In order to allow a user to sign up
  As a client software developer
  I need to be able to handle registration

  Background:
    Given there are Users with the following details:
      | uid | username | email          | password |
      | u1  | peter    | peter@test.com | testpass |
    And I set header "Content-Type" with value "application/json"

  Scenario: Cannot register with existing user name
    When I send a "POST" request to "/register" with body:
      """
      {
        "email": "peter@some-different-domain.com",
        "username": "peter",
        "plainPassword": {
          "first": "abc123",
          "second": "abc123"
        }
      }
      """
    Then the response code should be 400
     And the response should contain "The username is already used"

  Scenario: Cannot register with an existing email address
    When I send a "POST" request to "/register" with body:
      """
      {
        "email": "peter@test.com",
        "username": "different_peter",
        "plainPassword": {
          "first": "abc123",
          "second": "abc123"
        }
      }
      """
    Then the response code should be 400
     And the response should contain "The email is already used"

  Scenario: Cannot register with an mismatched password
    When I send a "POST" request to "/register" with body:
      """
      {
        "email": "gary@test.co.uk",
        "username": "garold",
        "plainPassword": {
          "first": "gaz123",
          "second": "gaz456"
        }
      }
      """
    Then the response code should be 400
    And the response should contain "The entered passwords don't match"

One thing to note here is that I am only checking that the returned response contains some text - not the whole response.

Consider, however, that your Behat scenarios / features serve as documentation to your project. In my opinion they serve as the best documentation to your project - and can often save you from having to answer the same questions over and over again. Let's take two real world examples from a recent project I have worked on.

Documentation For Other Team Members

"What should a valid response from /some-endpoint look like?"

You're working in a team of n+1 :) You're only responsible for some part of the application - let's imagine in this example that you are only responsible from the back end.

You've followed along with something similar to the system approach in this course, and now have a working API which front-end developers / API consumers wish to use.

Sure, there's the API docs - something like the awesome Nelmio API Doc Bundle - but this only goes so far. It shows a developer how to interact with your API, which methods / verbs can be used, the end-point name, and so on. There's even a sandbox, if enabled.

And that's great, but it does require the developer / consumer to send in their own requests, and work with the output as it comes back. Critically this doesn't tell that person if the response they got was the one you expected them to get.

I faced a similar problem. I kept getting questions about the expected outcomes for a variety of endpoints.

My solution: give the developers read access to the Behat scenarios. That way they could see the passing tests for themselves. Immediately the number of questions were dramatically reduced. Hurrah.

Documentation For Yourself

In the above scenario you are helping others, along with reducing your "support" burden.

This is great, but human nature is to be fairly self serving.

What if you do the role reversal on the above - but change the parameters slightly.

In a personal project - the revamped back end for CodeReviewVideos, currently a work-in-progress - I too am using this system for my API. I have a front end coded in React.

Now, as ever when working on personal projects, something will inevitably come along and completely sidetrack you. In my case it was some client work.

Coming back to the project after just 6 days was not much better than if I had been gone for 6 weeks.

Thankfully :) I had a ton of failing tests on the front end. Rather than worrying about adding new features right away, I began by tackling the failing tests. Almost immediately I was hit with an unexpected problem:

I understand how the system works when it goes down the happy path, but how does it handle errors? In fact, what do errors even look like, and how can I feed them into my front end tests? After all, the error response from the API is what my front end code must react too (no pun intended).

This led me to a similar situation as in the first example - using the Behat features as documentation. It also highlighted a failing in my Behat tests - the error / unhappy path examples were not in-depth enough. Including the error output would have been much more immediately beneficial.

The downside is, the more specific you are in the Behat features, the more brittle they become. As ever, it is a series of trade offs.

Code For This Course

Get the code for this course.

Episodes