Login - Part 2 - Being Careful of Edge Cases
In this video we add in all the potential unhappy paths we can think of for our Symfony 3 API login journey.
There's always one happy path. There's always at least one unhappy path. The pessimism is high.
Our login.feature
file now looks like this:
# /src/AppBundle/Features/login.feature
Feature: Handle user login via the RESTful API
In order to allow secure access to the system
As a client software developer
I need to be able to let users log in and out
Background:
Given there are Users with the following details:
| id | username | email | password |
| 1 | peter | peter@test.com | testpass |
| 2 | john | john@test.org | johnpass |
And I set header "Content-Type" with value "application/json"
Scenario: Cannot GET Login
When I send a "GET" request to "/login"
Then the response code should be 405
Scenario: User cannot Login with bad credentials
When I send a "POST" request to "/login" with body:
"""
{
"username": "jimmy",
"password": "badpass"
}
"""
Then the response code should be 401
Scenario: User can Login with good credentials (username)
When I send a "POST" request to "/login" with body:
"""
{
"username": "peter",
"password": "testpass"
}
"""
Then the response code should be 200
And the response should contain "token"
Scenario: User can Login with good credentials (email)
When I send a "POST" request to "/login" with body:
"""
{
"username": "peter@test.com",
"password": "testpass"
}
"""
Then the response code should be 200
And the response should contain "token"
Ok, so positive outcomes at this stage?
We have a full set of passing tests!
Yes, we didn't have to write more code. This was to test all the other various states we anticipate our code having to respond too.
This is different to unit testing. This is writing tests to cover business needs. These are acceptance tests.
We've got the basis of our entire testing setup here.
We've covered most of the test step definitions we will use throughout the rest of this series. We've send data into, and had responses from our API.
These are big steps. The foundation of our system is in place.
Also, we can seed the database. We can define 'stuff' and ensure that the DB state is as expected at the start of our test cycles. This makes things much slower than typical unit testing. Real life doesn't come with the 350% time compressing I do in post-production for the videos ;)
Behat + Symfony 3 Profiler Tip
A really nice way to use Behat and Symfony 3 (or 2) together is in using the _profiler
route to really dig into the request through response lifecycle.
The way I do this is to annotate / tag my tests with @this
, and then run behat with the --tags
flag:
php vendor/bin/behat --tags=this
And you only run the single test you care about.
Actually, you can tag multiple tests in this way and run subsets, which is another approach to using tags that's equally useful.
Then, when you've run your test, browse the response headers and grab the X-Debug-Token-Link
header value:
X-Debug-Token-Link →http://api.rest-user-api.dev/app_acceptance.php/_profiler/8612ce
Browsing that takes you directly to the profiler for that exact request. Amazingly useful, and should be a major help in debugging any issues you run in too.