Testing POST Requests

Last week, I introduced the concept of the GET request and how to test it.  This week we’ll move to POST requests.  POST requests are perhaps the most important of the RESTful requests, because they are what adds new records to your application’s database.  It’s very important to test your POST requests well, because they will have a direct impact on the quality of data in your database.

To learn about POST requests, we’ll once again use the Swagger Pet Store and Postman.  Navigate to the Pet Store (http://petstore.swagger.io) and click on the first POST request listed: “/pet”.  This POST request will add a pet to the pet store.  Take a look at the Example Value shown:

This is the body of the POST request.  Unlike GET requests, which usually don’t have a body, you will usually find some json or xml in a POST request.  The body represents the data that you are adding to the database.  Now click on the Model link:

This describes a bit about what all of the values in the body are.  You can click on the “>” icons to open up each section of the model.  I find this model to be a bit vague in terms of defining what a category is and what tags are, so I’m going to do a little guesswork.  Let’s walk through each section of the Pet model:
id: this is the id of the pet, which can be used in the GET request we tested last week
category: this represents what kind of animal the pet is.  The id is the unique identifier for the category, and the name is the word describing the animal.
name: this is the pet’s name
photoUrls: these are strings that link to pictures of the pet
tags: these are descriptive phrases that can be added to the pet.  The id is the unique identifier for the tag, and the name is the descriptive word describing something about the pet
status: this is the status of the pet in the store.  The status can be available, pending, or sold.

We can use the information in the model to create a POST to make a new pet.  Click on the “Try it out” link, and replace the body of the request with this information:
  “id”: 102,
  “category”: {
    “id”: 1,
    “name”: “cat”
  “name”: “Grumpy Cat”,
  “photoUrls”: [
  “tags”: [
      “id”: 1,
      “name”: “blue eyes”
  “status”: “sold”

Before you click the Execute button, I do want to point out something in this POST request that is different from what you will most likely experience in the applications you test.  Generally, when you post an object with an id and that id already exists in the database, you’ll get a message that the record already exists.  In the case of the Pet Store, if that id already exists in the database, it will get overwritten with the object that you have posted.  
Now click the “Execute” button.  Take a look at what was returned in the body of the response.  You should see all the data you added.  It may be in a different order than it was in the body of the request, but that’s not important.
Let’s test to make sure that the new pet was really added!  Return to the GET pet/{petId} request, open it up, and click “Try it out”.  Enter “100” into the id field, and click “Execute”.  You should see the pet you added in the body of the response.  
Now that you have created a successful request in Swagger, let’s try one in Postman.  Open up the Postman application, and click on the plus button (+) to create a new request.  Click on the dropdown icon next to the word “GET” and choose “POST” instead.  Enter in the request URL: http://petstore.swagger.io/v2/pet. Click on the “Body” tab underneath the URL and select the “Raw” option.  In the body section just underneath, paste the request that you used earlier in Swagger.  You may want to vary it slightly by changing the id or the pet’s name.  
There’s one more step we need to do before we can send this request in Postman, and that is to add a header.  Headers are used in HTTP requests and responses to pass additional information to the server.  In this case, we need to tell the server what content-type to expect.  Click on the “Header” tab underneath the URL.  In the space underneath “Key”, add “Content-Type”.  In the space underneath “Value”, add “application/json”.  In this way, we are telling the server that it should look for a body in json format when we send our request.  Now click the “Send” button.  In the bottom half of the Postman window, you should see a 200 response code, and a response body that has all of the data you added.  Now you can use a GET request in Postman to check to make sure that your pet was added.  Return to last week’s blog post if you need help setting that up.  
Just as we found when we discussed testing forms, there are many different scenarios to test when testing POST requests.  First, we’ll want to test many Happy Path scenarios.  Try a number of different POSTs where you vary the id, the category of the pet and its id, the pet’s name, the photo URL, the tag and the tag’s id, and the status of the pet. You’ll want to make sure to test all three statuses of the pet: sold, available, and pending.  Also note that it’s possible to pass in more than one photo URL, and more than one tag.  Here’s an example of a body of a POST request where three photos and two tags are passed in:
  “id”: 102,
  “category”: {
    “id”: 2,
    “name”: “dog”
  “name”: “Snoopy”,
  “photoUrls”: [
  “tags”: [
      “id”: 2,
      “name”: “beagle”
      “id”: 3,
      “name”: “flying ace”
  “status”: “available”

Now that you have tested a number of Happy Path scenarios, it’s time to think about breaking the request.  First, you may have noticed in the Swagger Model that only two fields are required: the name of the pet, and one photo URL.  What happens if you pass in just those two fields?  
  “name”: “Snoopy”,
  “photoUrls”: [

We get a 200 response, and the pet has been added with an id that we can use to retrieve it.  What happens if there are no values in the body of the request?  What happens if one of the required fields is missing?  Now is a good time to experiment by passing in a variety of combinations of fields.  
It’s worth noting at this point that you may get a 500 response for nearly every error condition you provoke.  In a real-world application, you’d get more appropriate response codes with more appropriate error messages. 

Next, it’s time to take another look at passing in multiple URLs and tags.  How many URLs can you pass in before provoking an error?  How many tags can you pass in before you get an error?  
Now we’ll look at the limits of the values we are passing in.  For example, what happens if you create a pet with an id of 0?  What happens if you create one with the id of -100000?  What happens if you send in an id of “FOO” or $%^?  You can test this on all of the ids: the pet’s id, the category id, and the tag id.  How long are the text strings allowed to be?  How short are they allowed to be?  Are there any characters that are not allowed?  You’ll want to test the upper and lower limits of the strings, and verify that any forbidden characters are not allowed.  This is also a good time to test for SQL injection and cross-site scripting.  For example, you could try passing in 
‘ or 1 = 1– 
and see if those are allowed.  (In the case of the Pet Store, these will probably be allowed, but a real application should forbid these or at least render them ineffective.)  
Another thing to test is the enum field for the pet’s status.  The pet’s status should be limited to available, pending, and sold.  What happens if you pass in another word or number or symbol?  What happens if you pass in a valid status with all caps, or with some of the letters capitalized?  A POST request should generally be case-insensitive.  You will also want to test the photo URL, making sure that you can’t pass in malicious scripts, and making sure that you can’t pass in something that isn’t a URL.
Once you have finished testing the body of the request, you can test the headers of the request.  This particular POST request requires a Content-Type header, and it will allow either an application/json header or an application/xml header.  If the header is missing, you’ll get a 415 error.  If you use an application/xml header, you’ll get a 400 error, unless you first change the body of the request to be in XML format.  You could also test to see what happens when you send an xml body with an application/json header.  
Finally, you can test the URL of the request itself, and the request type.  What happens if you make the request an https request?  What happens if you change the POST request to a GET?  
In summary, there are many ways to test POST requests, many of which would not be possible if you were focusing only on the UI.  In addition to testing required and non-required fields and field validation, you can also manipulate the object passed into the database and the headers and URL used to make the request. 
Next week, we’ll move on to PUT requests!  

Testing GET Requests

Last week I introduced the concept of RESTful API requests, and discussed why it’s crucial that we test them in our applications.  This week, we will begin our discussion of RESTful request types with the GET request.  This is usually the easiest request to test, because all we are doing is retrieving data from the database.  We don’t need to worry about whether we are manipulating data correctly; we just need to retrieve it and check that we get a correct response. 

In my opinion, the two best tools to learn about REST requests are Swagger and Postman.  Swagger is an open-source framework that allows developers to create documentation for RESTful APIs.  If your API has a Swagger file, it’s easy to see what kinds of requests your API allows, and what sorts of parameters those requests are expecting.  The developers of Swagger have also created a sample application that you can use to practice making REST requests:  petstore.swagger.io.  This website simulates an online pet store, where users can enter and retrieve information about their pets.

When you go to the petstore.swagger.io website, you can see that there are a variety of requests available for the pet endpoint.  Let’s take a look at the GET /pet/{petId} endpoint.  Click on that request, then click on the “Try it out” button. You will notice that a petId is a required parameter.  Enter “1” into the parameter text field, and click the “Execute” button.  Scroll down to the Response Body section, and you will see that a pet has been returned!  Scroll up a bit and take a look at the Request URL: http://petstore.swagger.io/v2/pet/1. We will use this URL to learn about making requests in Postman.

Postman is the best tool that I have found for testing REST requests. It is available for free at https://www.getpostman.com, and there is also a paid Team version. If you don’t have it already, download Postman and start it up.

Postman should start up with an open tab, set to use a GET request. All you have to do now is enter the request URL that we used before, and click the “Send” button. You should get the same response that you did when you made the request in Swagger.

Now that we understand how GET requests work, let’s think about how to test them! We have obviously tested a Happy Path scenario where we are getting a pet with an id of 1. What happens if we change the id parameter to 2? What happens if we change the id parameter to -1? What if it’s 0? What if it’s “foo”? I should mention here that because the Swagger Pet Store is a test application, you may see results or behavior that would not be wanted in an application. For instance, when I tested with a parameter of -1, I got a result. It’s a fairly common expectation that the ids of data objects not be negative numbers, so this would be a bug in a real application.

Let’s find out what happens when we don’t enter any parameter at all, so our request URL is just http://petstore.swagger.io/v2/pet. We get an xml response that says “unknown”. You may also notice that the status code returned is “405 Method Not Allowed”.

The status codes you get after you make a REST request tell you a bit about the behavior of your application.  We’ll discuss status codes further in a later post, but for now, let’s note that a status code of 200 is good, and a status code that begins with 4 generally indicates that something has gone wrong.  You may get a 404 status when you search for a pet id that doesn’t exist.  This means that the record was not found. 

Let’s return now to the Swagger Pet Store and take a look at another GET request.  This time, we will look at the pets/findByStatus request.  Click on the request, and then click the “Try it out” button.

Note that in order to execute this request, you need to select a status.  Let’s click the “sold” status and then click the “Execute” button.  If you scroll down to the response window, you can see that many pets were returned.  Now scroll up a bit and take a look at the request URL that was used: http://petstore.swagger.io/v2/pet/findByStatus?status=sold.

The question mark in the URL indicates that we are using a query parameter.  This is a little different from the path parameter we saw when we were doing a GET by pet id.  Query parameters always begin with a question mark, and then have the parameter name, an equals sign, and the value of the parameter we want to use.  

Let’s copy this request and run it in Postman.  Simply use the + button near the top of the screen to open a tab and create a new request.  It should be a GET request by default.  Enter the URL and click “Send”.  You should get the same result that you saw when you ran the request in Swagger.  

We have now tested one Happy Path for this request.  You can also run the request using the “available” parameter and the “pending” parameter.  You could run this request: http://petstore.swagger.io/v2/pet/findByStatus?status=pending,sold and get all of the pending pets and all of the sold pets!  What happens if you send a value of “foo” for the status parameter?  You will get an empty set [ ] as a result.  This is different from what we saw when we sent in “foo” as the parameter for the GET pet by pet ID request.  This demonstrates the difference between a path parameter and a query parameter.  When a path parameter does not exist, you will generally get a 400-level response code.  When a query parameter does not exist, you will generally get a 200 response code and an empty set in the response body.  

Now that you have tried out two different GET requests, you can test further by manipulating the request URL in any number of ways.  For example, you could see what happens if you make the request an https request instead of http.  You could find out what happens if you change the “io” in the request to “com”.  You could change the “v2” to “v1”.  You could remove the “/pet” endpoint.  You could try changing the GET request type to a POST or a DELETE type.  Seeing what happens when you manipulate the URL and the request type will give you a sense of how REST requests work, and will also give you ideas for what you could test in an API that you are responsible for. 

I hope that this post has demonstrated just how easy API testing is, and also how versatile it can be.  With API testing, you can test many scenarios that would not be possible to test through the UI.  This is a valuable strategy to use in finding potential design and security flaws earlier in development.  Next week, we’ll move on to POST requests!

Introduction to REST Requests

More and more companies are moving toward a microservices model for their applications.  This means that different sections of their application can have a separate datastore and separate commands for interacting with that datastore.  The advantage to this is that it’s easier to deploy changes to a small component of the application rather than the entire application; it also means that if one microservice goes down, the rest of the application can continue to function.  For example, let’s imagine you have a website for a bike rental service.  The site has a microservice for the reservation system, and a second microservice for the inventory.  If the microservice for the inventory goes down, users will still be able to make reservations for bike rentals, using cached data from the inventory microservice.

Most microservices are using APIs, or Application Programming Interfaces, which are a set of commands for how a service can be used.  And most APIs are using REST requests, or Representational State Transfers, through HTTP to request and send data.

Yet in spite of the common usage of RESTful APIs in today’s applications, many testers do not know just how easy it is to test them!  This post will serve as a gentle introduction to REST requests for use in API testing.

Why would you want to test REST requests, rather than just wait and test through the UI?  Here are a few good reasons:

  • testing REST requests means that you can find bugs earlier in the development process, sometimes even before the UI has been created!
  • malicious users know how to make REST requests, and can use them to exploit security flaws in your application by making requests the UI doesn’t allow
  • it’s easy to automate REST requests, and they run MUCH faster than UI automation (see my earlier blog post for further discussion of API vs. UI automation)
To get started in RESTful testing, first think about what you see in a URL when you navigate to a website.  For example, you might see: https://www.foobank.com/customers/login.  It’s easy to see how this URL is defining what page you are navigating to:
  • the https is specifying that this is a secure request
  • the www.foobank.com is the domain, which says that you want to go to the Foobank website
  • the customers is the first part of the path, which says that you are a customer and therefore want to go the Customers section of the website
  • the login is the last part of the path, which says that you want to go the login screen
One thing that’s not seen in the URL is the type of RESTful request being made.  This is known as an HTTP verb, and they are easy to understand:
  • a POST request adds a new record to the database
  • a GET request retrieves a record from the database
  • a PUT request takes a record from the database and replaces it with a new record
  • a PATCH request modifies an existing record in the database
  • a DELETE request removes a record from the database
In this case, a “record” can be any section of data that is grouped together.  For example, it could be a mailing address for a customer; or it could be all of the contact information for that customer; or it could be every single datapoint associated with that customer.  It’s up to the creators of the API to decide what should make up the record.  
In the next several blog posts, I’ll discuss each of the HTTP verbs in detail and describe how to test them.  I am sure you will be excited to discover just how much you can test without even navigating to your application’s web pages!

Testing the Login Screen

The login screen is the first line of defense between your application and a malicious unauthorized user.  But it’s so easy to forget about testing the login screen!  This is because as a tester, you are in the application every single day.  Getting past the login screen is a step you take dozens of times a day to get to whatever feature you are currently testing.

Let’s take some time to look at the various ways we should be testing login screens.

First, make sure that the password field masks text as you type in it.  Next, check to make sure that both the username and the password fields are expecting case-sensitive text.  In other words, if your username is “FOO” and your password is “bar”, you should not be able to log in with “Foo” and “Bar”.

Next, find out what the validation requirements are for the username and password fields.  How short can the values be?  What’s the longest they can be?  What characters will be accepted?  Verify that the length requirements are respected in both fields, then test with every non-accepted character that you can think of.  Be sure to test with non-UTF-8 characters and emojis as well.  You may have heard a story several years back of a bank customer who broke the application by setting her password to have an emoji in it!

Also be sure to test for SQL injection.  For example, if you enter 1′ or ‘1’ = ‘1 into the password field, you may be telling the database to return ‘true’ and allow logging in, because of course ‘1’ always equals ‘1’.

Now let’s test with every possible combination of username and password states.  Each field can be either empty, incorrect, correct but with the wrong case, and correct.  This generates sixteen possible combinations:

It may seem like overkill to test all these combinations, but I have seen situations (fortunately that were only in the earliest stages of development) where I could log in with an empty username and password, or log in where both the username and password were incorrect!

Another helpful thing to test is putting an empty character or two at the beginning or end of the fields.  When the user submits their login request, empty characters should be stripped from these values.  If this does not happen, the user may wind up with a situation where they have typed their correct password: “bar “, and the password is not accepted because of the space at the end.  This is very frustrating for an end user who doesn’t know the empty character is there.

Next, let’s think about the kind of error message you are getting when you try to login with invalid credentials.  You don’t want to give a malicious user any kind of hints about whether they have guessed a username or a password correctly.  If the malicious user types in “FOO” for the username and “password” for the password, you don’t want to return a message that says “Invalid password”, because this will let the malicious user know that the username is correct!  Now all they have to do is keep the username the same and start guessing at the password.  It is much better to return a message like “Invalid credentials”.

Now let’s take a look at what is passed into the server when you are making a login request.  Open up the developer tools for the browser you are using, and watch the request that goes through.  Do you see the username or the password in clear text anywhere?  If you do, this should be fixed!  Usernames and passwords should both be encrypted in the request.  You can also check the request by using an interception tool like Fiddler or Burp Suite.

Once you have logged in with correct credentials, take a look at the cookie or session id that has been set for your user.  Do you see the username and password anywhere?  All cookies, web tokens, and session ids should not include the user credentials, even if they are encrypted.

Finally, be sure to test logging out!  When you log out, the username and password fields on the login screen should be cleared, unless there is a feature to remember the credentials.  If there is such a feature, the password should definitely be masked and should give no indication of how many characters are in it.  Upon logging out, any session ids or web tokens should be deleted.  If there is no feature to remember credentials, the cookie should be deleted as well.  There should be nothing that you can grab from developer tools or interception tools to use to pretend that you are logged in.

This is a lot to test; fortunately, we can take advantage of automation for regression testing once we have done an initial test pass.  Here are a few ideas for what to automate:

API login calls using all the combinations of username and password listed above
UI logins with too many characters and invalid characters in the username and password fields; verify that the error message returned is the correct one
Visual testing of the login screen to verify that the password is not displayed in clear text (a good tool for visual testing can be found at https://www.applitools.com)

Security is such an important part of any application!  By running through all of these login scenarios, you can help bring peace of mind to your product team and to your end users. 

Testing Back Buttons

The back button is so ubiquitous that it is easily overlooked when it comes to web and application testing.  The first thing to know when testing back buttons is that there are many different types.  The two major categories are: those that come natively, and those that are added into the application.

For native buttons, there are those that are embedded in the browser, those that are embedded in a mobile application, and those that are included in the hardware of a mobile device.  In the photo above, the back arrow is the back button that comes with the Chrome browser.  An Android device generally has a back button at the bottom that can be used with any application.  And most iPhone apps have a back button built in at the top of every page.

Added back buttons are used when the designer wants to have more control over the user’s navigation.  In the example above, the Home button is used to go back to the W3 Schools home page.  (I should mention here that W3 Schools is an awesome way to learn HTML, CSS, Javascript, and much more: https://www.w3schools.com/default.asp)

When you are testing websites and applications, it’s important to test the behavior of ALL of your back buttons, even those that your team didn’t add.  The first thing to do is to think about where exactly you would like those buttons to go.  This seems obvious, but sometimes you do not want your application to go back to just the previous page.  An example of this would be when a user is editing their contact information on an Edit screen.  When the user is done editing, and has gone to the Summary page, and they click the Back button, they shouldn’t be taken back to the Edit screen, because then they’ll think they will have to edit their information all over again.  Instead, they should go back to the page before.

Another thing to consider is how you would like back buttons to behave when the user has logged out of the application.  In this case, you don’t want to be able to back into the application and have the user logged in again, because this is a security concern.  What if the user was on a public computer?  The next user would have access to the previous user’s information.

For mobile device buttons, think about what behavior you would like the button to have when you are in your application.  A user will be frustrated if they are expecting the back button to take them elsewhere in your app, and it instead takes them out of the app entirely.

If your application has a number of added back buttons, be sure to follow them all in the largest chain you can create.  Look for errors in logic, where the application takes you to someplace you weren’t expecting, or for memory errors caused by saving too many pages in the application’s path.

You can also check whether the back button is enabled and disabled at appropriate times.  You don’t want your user trying to click on an enabled back button that doesn’t go anywhere!

In summary, whenever you are testing a web page or an application, be sure to make note of all of the back buttons that are available and all of the behaviors those buttons should have.  Then test those behaviors and make sure that your users will have a positive and helpful experience.

Automated Form Testing

Now that we have looked at all the different ways we can manually test forms, it’s time to think about automating those tests so you don’t have to run through all the tests again every time you need to do a regression test!  But before you jump into automation, think for a while about what tests you really want to run.  Let’s take last week’s form as our example again.

What sorts of things would we want to make sure still work when we do our regression test?

  • We’ll want to make sure that every field can be populated with data and saved
  • We’ll want to make sure that all of the required fields are still required, and that we get an appropriate error message when we leave a required field blank
  • We’ll want to make sure that validation rules are respected in each field
  • We’ll want to verify that both the Save and the Cancel buttons work correctly
As I’ve discussed in a previous post, automated tests involving the GUI can often be slow and flaky.  So we’ll want to limit the number of times we spin up a browser for testing.  But we’d also like our tests to only assert on one thing at a time.  Here are my suggestions for a suite of tests that could be run on this form.  I’ve written them in Cucumber for ease of reading:
Scenario: Happy Path
Given I am adding a new user
When I fill out all the fields and click the Save button
And I navigate to the Users page
Then I verify that all of the fields are displayed on the page
Scenario: Required Fields
Given I am adding a new user
When I leave all fields empty
And I click the Save button
Then I verify that an error message is present for each required field
Scenario: Validation Rules
Given I am adding a new user
When I give each field an invalid value
And I click the Save button
Then I verify that an error message is present for each invalid field
Scenario: Cancel Button
Given I am adding a new user
When I give each field a value
And I click the Cancel button
Then I verify that all fields are now empty
So, we can cover a lot of territory with just four automated tests!  
Our Happy Path tests that values in all of the fields will save correctly, and it also tests the Save button.  If one of the values does not save, we will know we have an error.  If all of the values do not save, we will know there is a problem either with the Save button or with the underlying data store. 
Our Required Fields test checks to make sure that every field that is required displays an appropriate error message if it is not filled out.  If even one required field does not display the message, we will know there is a problem.
Our Validation Rules test violates one rule for each text field.  It would be a good idea to mix and match the different types of rule violations.  For example:
First Name- send a value with numbers and non-letter characters, such as $23.00
Last Name- send a value with not enough letters, such as A
Personal Phone- send a value with the wrong number of digits, such as 008675309
Work Phone- send a value with non-number characters, such as 800*555-!@#$
Street Address 1- send a value with way too many characters, such as all the lyrics to “Frosty the Snowman” (my favorite song to test with)
Street Address 2- send a value with one too many characters
City- try sending a script, such as <script>alert(“XSS Here!”)</script>
State- send an invalid state, such as XX
Zip Code- send a Zip Code with the wrong number of digits, such as 0377
While this does not test every single way that the rules could be violated in every text field, it covers a wide variety of possibilities, and verifies that for each error, you receive an appropriate error message.  You could always add more tests here if you felt that more coverage was needed.
Finally, we verify that the Cancel button works correctly.  
With just these four automated tests, we’re able to make sure no functionality is broken.  Running these regression tests will free you up to do more exploratory testing in your application, and to test new and more interesting features!

Testing Forms

Today is the day that we’ll be putting it all together!  In the past few posts, we’ve been looking at different types of text fields and buttons; now we’ll discuss testing a form as a whole.

There are as many different ways to test forms as there are text field types!  And unfortunately, testing forms is not particularly exciting.  Because of this, it’s helpful to have a systematic way to test forms that will get you through it quickly, while making sure to test all the critical functionality.

Let’s take a look at the form below, and I will walk you through a systematic approach to testing it.  For simplicity, we’ll assume that the users will all be US-based.  (See my previous posts for discussions on testing international postal codes and phone numbers.)

Step One:  Required Fields

The first thing I do when I test a form is to make note of which fields are required.  This particular form denotes required fields with a red asterisk.  We can see that First Name, Last Name, Personal Phone, Street Address 1, City, State, and Zip Code are all required.  I want to verify that the form cannot be submitted when a required field is missing and that I’m notified of which field is missing when I attempt to submit the form.
1. I click the Save button when no fields have been filled out. I make sure that all of the required fields have error messages.
2. I fill out the two non-required fields, click the Save button, and verify that all the required fields have error messages.
3. I fill out one required field and click the Save button, and I verify that all the other fields have error messages.  I start with submitting just the First Name, then just the Last Name, then just the Personal Phone, etc., until I have cycled through all of the required fields.
4. I try various combinations of two, three, four, and five required fields to make sure the appropriate error messages are displayed.  I don’t concern myself with testing every possible combination, since it’s highly likely that the required field will behave similarly in these situations.
5. I try filling out all the required fields but one, and verify that I still receive an error for that field.  I cycle through all the possibilities of having one missing required field.
6. I fill out all of the fields- required and non-required- except for one required field, and verify that I still receive an error.
7. I fill out all of required fields and click the Save button, and I verify that no error messages appear and that the entered fields have been saved correctly to the database.
8. Finally, I fill out all of the fields- required and non-required, and I verify that no error messages appear and that the entered fields have been saved correctly to the database.

Step Two: Field Validation

The next thing I do is verify that each individual text box has appropriate validation on it.  First, for each text field, I discover what the upper and lower character limits are.  I enter in all the required fields except for the one text box I am testing.  Then in that text box:
1. I try entering just one character
2. I try entering the lower limit of characters, minus one character
3. I try entering the upper limit of characters, plus one character
4. I try entering a number of characters far beyond the upper limit
In all of these instances, the form should not save, and I should receive an appropriate error message.
5. I enter the lower limit of characters, and verify that the form is saved correctly
6. I enter the upper limit of characters, and verify that the form is saved correctly

Now that I have confirmed that the limits on characters are respected, it’s time to try various letters, numbers and symbols.  For each text field, I find out what kinds of letters, numbers, or symbols are allowed.  For example, the First and Last Name fields should allow apostrophes (ex. O’Connor) and hyphens (ex. Smith-Clark), but should probably allow no numbers or symbols.  For each text field:
1. I try entering all of the allowed letters, numbers and symbols
2. I try entering the letters, numbers, or symbols that are not allowed, one at a time, until I have verified that they are all not allowed

For fields that have very specific accepted formats, I test those formats now.  For instance, I should be able to enter a Zip Code of 03773-2817, but not one of 03773-28.  For the State field, the two-letter code I put into the field should be a valid state, so I should be able to enter MA, but not XX.

Even though I’ve already tested all the forbidden numbers and symbols, I try a few cross-site scripting and SQL injection examples, to make sure no malicious code gets through.  (More on this in a future post.)

Step Three: Buttons

Even though I have already used the Save button dozens of times at this point, there are still a few things left to test here.  And I have not yet used the Cancel button.  So:
1. I click the Save button several times at once, and verify that only one instance of the data is saved
2. I click the Save button and then the Cancel button very quickly, and verify that the data is saved and that there are no errors
3. I click the Cancel button when no data has been entered, and verify that there are no errors
4. I click the Cancel button when data has been entered, and verify that the data is cleared.  I’ll try this several times, with various combinations of required and non-required fields.
5. I click the Cancel button several times quickly, and verify that there are no errors

Step Four: Data

Finally, it’s time to look at the data that is saved.  In earlier steps, I’ve already done some quick checks to determine if the data that I am entering is saved to the database.  Now I’ll check:
1. That bad data I’ve entered is not saved to the database
2. That good data I’ve entered is saved to the database correctly
3. That good data I’ve entered is retrieved from the database correctly, and displayed correctly on the form

If the form I am testing has Edit and Delete functionality, it’s important to test these as well, but I’ve covered these in my post CRUD Testing Part II- Update and Delete.

Once I’ve gone through a form in this systematic way, it’s almost certain I will have found a few bugs to keep the developers busy.  It’s tedious, yes, but once the bugs have been fixed I can move on to automation testing with confidence, knowing that I have really put this form through its paces!

Testing Buttons

Buttons tend to be something that it’s easy to forget about.  The “Save” button is so ubiquitous that it seems like it would just work.  But overlooking testing buttons on a page can also mean overlooking bugs.  Recently someone told me about new functionality she was testing on an existing web page.  The new feature worked great, but her team forgot to test the “Delete” button.  It turned out that the developers had forgotten to account for the delete action in their new feature, and now “Delete” did nothing! 

Here are a few things to think about when testing buttons:

1. Test the “happy path” of the button.  Usually buttons have some sort of message on them that tell you what they are supposed to do.  So try it out, and make sure that the button delivers on its promise!  Did the “Save” button really save your data?  Did the “Delete” button delete it?  Did the “Clear” button clear it?  Did the “Search” button execute a search?  (Note: a “Back” button is also common, but back buttons are tricky enough that I will be saving them for a separate post.)

2. Misuse the button.  For example, quickly press the “Save” button twice when adding data.  Were two records saved instead of one?  Does a button get confused when you press it twice?  What about when you quickly press one button and then another?  One of the most amusing bugs I have found in my career was a “Refresh” button that redrew the screen, making the button larger whenever I pressed it.

3. Is the button there when it’s supposed to be?  When we have spent a lot of time testing an application, it’s easy to get used to the page and not notice when things are missing.  Think about your user stories when looking at the page.  What would your user need when doing certain activities on that page?  Follow the path that the user would take, and check for the buttons as you go.

4. Think about when the button is enabled and when it is disabled.  Does it make sense?  For example, is the “Save” button only enabled when all the required fields on your form have been filled out?  Is the “Clear” button only enabled when a field has been dirtied?  How do you know the button is enabled?  Can you tell by looking at it?  Does the button look enabled when it isn’t?  Does the button look disabled when it’s really active?  What happens when you press the button and it’s not enabled?  Do the enabled and disabled rules for the button make sense?

5. Finally, see if you can hack your buttons!  For example, if you have a “Save” button that is disabled on your form because some of the required fields are missing, can you edit the html on the page so that it is enabled, and can you then use the button?  If you view the html and you see that there is a hidden button on the page, can you make it visible and active?  At best, that bug is an annoyance that will get inaccurate data into the database.  At worst, the bug represents a way that a hacker can infiltrate your system!  Imagine that you have a button that should only be visible and enabled if a user is an administrator.  If a malicious user can make that button appear on the screen and be active, they will have access to pages or features that only an admin should have. Your developer should include checks whenever a button is clicked on to make sure that the user has the rights to do what the button does. 

If you have never edited the html on a web page while testing, here are a few simple instructions for the Chrome browser:
a. Click on the three-button menu on the top right of your screen, and choose “More Tools -> Developer Tools”.  A new panel will appear on the bottom or the right side of your screen.
b. Right-click on the button you want to test, and click “Inspect”.  In the developer tools panel, you will now see the html for that button highlighted.
c. Right-click on that highlighted text and choose “Edit as HTML”.  An editable text window will open up. 
d. If you see text such as “‘disabled’=disabled” delete the text.  Click away from the editable field, and see if your button is now enabled. If it is, click on it and see what happens!
e. To find hidden buttons, look at the html in the developer tools, and use the search bar to search for “button”.
f. If you find a button with the markup “ng-hide”, try changing it to “ng-show”.  See if you can get the button to appear on the page!

Buttons are one of the most important things to test.  Just imagine a user’s frustration if the button they are trying to use is disabled, or doesn’t do what they expect it to.  By being diligent in our testing, we can ensure that our users will want to work with our application. 

Testing Phone Fields- Part II- International Phone Numbers

If I were to be given three wishes for the world, my third wish (after world peace and ending world hunger) would be to standardize international phone numbers, because testing them is so complicated!  Let’s take a look at some phone number patterns from around the world:

Phone numbers are ten digits, plus an area code of either two digits or three digits.  So the local number will be either twelve or thirteen digits.

Landline numbers are generally nine to eleven digits, but some can be as short as six.  Mobile numbers are usually ten digits, but there are also some nine-digit numbers.

Telephone numbers in Japan have an area code, an exchange number, and a subscriber number.  Area codes can have between two and five digits.  Generally the length of the entire number is limited to nine digits, so if the area code is longer, the exchange and subscriber numbers will be shorter.

Now let’s think about international calling codes.  Calling codes can range from one digit (such as the US’s +1) to three digits (such as +351 for Portugal).  So between the international calling codes and the phone number itself, there is a wide range of the number of digits that might be expected for a phone number.

Finally, let’s think about number separation.  While US numbers are always separated in a 3-3-4 pattern, in other countries the numbers can be grouped in various ways.  Here are just some of the ways that phone numbers are grouped in England:

(xxx) xxxx xxxx
(xxxx) xxx xxxx
(xxxxx) xxxxxx
(xxxx xx) xxxxx

Therefore, it is extremely difficult to validate on whether the pattern of numbers, parentheses, and dashes entered by a user is correct.

So how on earth are we to validate international phone numbers?  The most important thing to do is to make sure that the developer doesn’t try to come up with a validation regex on their own- that will make them (and you) go crazy!  Fortunately an international phone number formatting standard called E.164 has been developed.  Many companies such as Microsoft and Google have come up with regex patterns that can be used for E.164 validation.  For testing, there are free websites that will let you know if an international phone number is valid.  Most of these sites will require some sort of registration.  You can come up with a list of international numbers to test, verify with the website to see if they are valid, and then try them in your application.  For negative testing, simply use a sampling of invalid numbers and verify that you get an appropriate error message.

What format should a user use when entering in their phone number?  Some users might want to put parentheses, spaces, or dashes into their number.  Then there is the plus sign, which is used to indicate a country code.  For simplicity’s sake, it would be best to expect nothing but digits and a plus sign.  It would also be good to prompt the user for what format the application is expecting.  For example, in the United States you might have a message such as: “Enter your phone number with no dashes, parentheses, or spaces.  For numbers outside the US, a plus sign (+) and the country code should be used.”  Then for validation, if the number does not have a plus sign, simple US number validation rules can be applied, and if the number does have a plus sign, international validation rules can be applied.

Similarly, you may want to store the number in the database with the plus sign, to indicate that the number is an international one.  How should the numbers be displayed when retrieved in the application?  For many countries it’s nearly impossible to know how the numbers should be spaced, unless the validation code you are using returns that to you.  If your country has a standard number formation, you can display the number in that standard.  If your country does not have a standard formation, or if you are displaying a number from outside your country, you can simply display the number as is, such as: +442073238299.

When it comes to international phone numbers, there really are no easy answers, which is why I am wishing for world standardization!  There are other ways to (mostly) solve the problem, such as 1) expecting only between 6 and 20 digits, not validating the number beyond making sure that it’s within that number of digits, and displaying the number as entered, or 2) having a separate field for the country code, validating the number for that specific country, and formatting the number according to that validation.  What is most important is that you communicate closely with the developer to decide on a clear strategy and test it accordingly.

Testing Phone Fields- Part I- US Phones

Phone number fields are without a doubt the most time-consuming thing I have ever tested.  This seems so unlikely- phone numbers are standardized to ten digits in the US, so how can they cause so many headaches?  The answer is that, as we saw with Zip codes, there are so many ways to get them wrong.

If you are fortunate enough to be testing a new application without any existing data, you can fend off most phone number headaches by clearly establishing validation rules for phone number fields.  The easiest type of validation is one that accepts ten digits only, and no other characters.  The developer can rely on UI formatting to put the number in an easily-readable format rather than expecting the user to do it themselves.  The reason why this is the best course of action is that allowing the user to add in formatting creates all sorts of ambiguity.  If my phone number is 800-867-5309, how might I type that in?  Just with dashes, or will I use parentheses, such as (800) 867-5309?  What about the older format of 1-800-867-5309?  With that format, I now have eleven digits.  
Many developers try to accommodate all styles in the mistaken notion that this will make things easier for the user, but this actually makes things much more complicated.  If both parentheses and dashes are allowed, there needs to be some sort of regex used for the validation.  Otherwise, a user could type in something like ((800)–867 5309 and the number will be accepted.  If the developer you are working with has decided that he or she would like to make it easy on the user by accepting parentheses and dashes, try entering values like 800–867–5309, 800(867)5309, and 8-0-0-867-5309.  After you have demonstrated that it’s possible to enter a badly formatted phone number, the developer’s strategy may change.

As with Zip codes, it’s important to consider how the phone number is saved to the database.  The best strategy for US phone numbers is to strip out any formatting and save the number as just the ten digits.  That way the number can be displayed in any way the UI designer deems appropriate.

Next, it’s time to think about how bad phone numbers will be displayed to the user.  If a number has been saved with formatting, will it be displayed with that formatting?  Will some attempt be made to strip the formatting?  Will it be displayed at all?  I have seen all kinds of bad numbers in databases.  One of my favorites was “dad’s office number”.  No one can format that!  A good strategy would be to format any ten-digit number by stripping out all of the non-number characters, and then adding in whatever format is desired for display.  If the phone number is eleven digits and starts with a 1, the leading 1 could be stripped off and then the number could be formatted for display.  With any other values, the “number” could be displayed as-is, or it could not be displayed at all.  Whatever is decided, it’s important to test with whatever bad numbers are currently in the database. 

Another wrinkle not often considered is phone extensions.  Many offices still use extensions to direct a call to a specific person.  Sometimes phone fields allow extensions as part of the number, but this is a bad idea, for the same reasons that allowing the user to format their own number is a bad idea.  Phone extensions can be any number of digits, so allowing them as part of the phone number means that now the validation can’t expect a specific number of digits.  Also, how might the user indicate that an extension is part of the number?  Will they enter 800-867-5309 ext. 1234800-867-5309×1234?  Allowing these types of variations will mean allowing letters and other characters, which it makes it more difficult to validate.  A far better solution is to include a separate field for an extension.  If your developer expresses interest in including the extension as part of the phone field, some testing with entries like 8008675309extextext…1234 will probably dissuade them. 

Finally, remember to test editing phone numbers, especially numbers that are in an incorrect format.  What will happen when the user has a phone number like 800-867-530 and tries to edit another field on the form?  Will they be notified upon saving that the number is incorrect and needs fixing?  This can be a good way to involve users in cleaning their own data.  What should happen when the user tries to fix an invalid number?  Ideally they should be able to save the value with a new valid number. 

I hope that this post has emphasized the importance of having good phone field validation.  If you are fortunate enough to be testing a brand-new application with an empty database, taking good care to ensure that only valid phone numbers are saved to the database, you will prevent many testing headaches in the future! 

This post only tackled United States phone numbers.  In my next post, I will take on the even greater challenge of international phone numbers!