Email Subscription Form

Saturday, March 3, 2018

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": [
    "https://pbs.twimg.com/profile_images/948294484596375552/RyGNqDEM_400x400.jpg"
  ],
  "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": [
    "https://schulzmuseum.org/wp-content/uploads/2017/06/920608_FlyingAce-200.jpg",
    "https://www.calmuseums.org/images/snoopy/snoopy.png",
    "https://vignette.wikia.nocookie.net/peanuts/images/2/28/AmigosperdemoSono.png/revision/latest?cb=20110823202539"
  ],
  "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": [
    "https://schulzmuseum.org/wp-content/uploads/2017/06/920608_FlyingAce-200.jpg"
  ]
}

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 
<script>alert('XSS')</script> 
or 
' 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!  





4 comments:

  1. "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 $%^?"

    WHAT???
    Fire this man who write such app, because nobody can create id except the application itself.

    ReplyDelete
    Replies
    1. Hi test_man! You are absolutely right that no one should ever write an application where the ids are created by the user rather than automatically assigned by the database. However, I have seen this kind of thing in legacy applications. Ideally, no application should allow a POST to include an id created by the user, but if you find one that does, you should at least make sure that the id is validated in some way.

      Delete
    2. I should have put a "sarcasm" tag :)

      Delete

Automation Wheel Strategy: Moving from What to How to When to Where

Last week , we talked about how I would decide what to test in a simple application in terms of testing every segment of the Automation Test...