Saturday, February 24, 2018

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!

Saturday, February 17, 2018

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!

Friday, February 9, 2018

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. 



Saturday, February 3, 2018

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 imbedded in the browser, those that are imbedded 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.