Friday, November 14, 2014

Test your RESTful API using PowerShell

Before I get into the "how" on this topic, I want to start by addressing the "why" and "when", as in "Why / When the heck would I want to do this?" Here are some situations I've run into or thought of where having a functional test script was (or could be) rather handy:

  1. You have unit tests for your API, but also want some "client-facing" tests as well.
  2. You want to make sure when a new build is posted, the routes operate as they did before.
  3. You inherited an API that you need to maintain, but there are no unit tests.
  4. You need to provide some kind of automated test for your application, but do not have time / budget to write a full suite of unit tests.
  5. You do not like writing unit tests, but still need some kind of test coverage solution.
  6. You REALLY like automated tests, and can't get enough of them :).

So now with some (mostly) real-world uses in mind, let's take a look at how this can be accomplished with PowerShell. My code is posted below; take a minute to scroll down and read it, then come back up to the next paragraph. I want to point out a few nuances that will make more sense within the context of the code sample.

Finished? Cool - let's dig into the nitty-gritty:

Invoke-RestMethod vs. Invoke-WebRequest

If you read the code carefully, you probably noticed that I've used two different PowerShell functions to call the API - Invoke-RestMethod and Invoke-WebRequest. Gah? Why not just use one or the other? Well, I ran into a known issue while writing a test script for an API I built recently, and this was the recommended workaround. Essentially, if you're going to make multiple subsequent PUT or DELETE requests from a PowerShell script (which you'll probably want to do at some point), Invoke-WebRequest is the method to use for those HTTP Verbs.

-SecondsAllowed

Each of my RunRoute functions in the script has a $SecondsAllowed parameter. This allows you to do strict performance testing of your routes (should you choose to do so) by specifying the number of seconds until the route times out when you call each function using the -TimeoutSec parameter. If you don't want to set a timeout for certain tests, just pass a zero.

-DisableKeepAlive

I include this parameter on every request. According to the documentation, this tells PowerShell to "[establish] a persistent connection to the server to facilitate subsequent requests.". That seems harmless, but in a production setting, we have no clue IF there will be subsequent requests by the caller. I've noticed test scripts will run slightly faster without this parameter, which can disrupt the timing of the -TimeoutSec check discussed in the previous paragraph, and potentially cause you to get a false sense of "real-world" performance.

-Headers

Invoke-RestMethod allows for a -Headers parameter, but I'm not using it in the code sample. The test API is very basic, and doesn't require me to provide any headers to interact with it. However, I want to mention it here because you'll likely need to add this to tests for a production API, since this is usually where you would exchange security information with the server. The param accepts a hash object like so:
$RequestHeader = @{};
$RequestHeader.Add("Key", $Value);
Invoke-RestMethod ... -Headers $RequestHeader;
You can put as many custom headers into this collection as needed. Check the documentation for further details.

LOG_FILE

I don't specify where to create the log file; it should default to - C:\Users\{your-name}. Just update this variable to change the output location. The log will contain an entry for each RunRoute call you make, indicating PASS or FAIL of the executed route, as well as total run time for all of the routes in your script.


Here's my sample script. The API which I wrote the tests against (jsonplaceholder) is publicly accessible, so you should be able to just download the code and start running it. I'm hoping once you've done that and stepped through it a few times, it will be fairly clear how you can modify the structure I've provided to fit your specific API.

* Like this script? Have a look at some of the other PowerShell scripts I've published.

2 comments:

  1. This is a really nice way to get extra coverage of API unit tests. Thanks for the tip!

    ReplyDelete
    Replies
    1. Hey Kieran, great to hear from you! Thanks for the feedback; glad you found the article useful. Hope you're doing well; drop me a message sometime and let me know how things are going.

      Delete