Testing REST API Using Test Studio

9 posts, 0 answers
  1. Tim
    Tim avatar
    5 posts
    Member since:
    Nov 2013

    Posted 19 Nov 2013 Link to this post

    Requirements

    RadControls version N/A
    .NET version 4.5
    Visual Studio version 2013.1.911.0
    programming language C#
    browser support

    all browsers supported by RadControls


    PROJECT DESCRIPTION
    This project makes use of the new HttpClient Class in the .Net Framework 4.5. This is much easier to use than the WebRequest/WebResponse Class in older .Net frameworks.

    I have included an example project, but will detail the steps of making your own.

    Add the Assembly Reference
    After installing the .Net Framework 4.5, follow the Telerik Article on adding the assemblies to your project. The .dll files are likely in these locations:
    • C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Net.Http.dll
    • C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Net.Http.Formatting.dll

    Add the Using Directives to your .CS Files
    For every .cs file (created when you make a coded step with C# as your language), add the following using directives:
    • using System.Net.Http;
    • using System.Net.Http.Formatting;

    Create Your HttpClient Container
    The HttpClient/session will be disposed after the test(s) is ran. To prevent this, and to allow multiple tests with the same session, you must contain the HttpClient in its own class. This will allow you to have multiple tests like; login, get a record, delete a record, and then logout.
    To make an HttpClient container, make a new web test. I like to make a folder for reused modules called, "Modules". In that folder I make a web test called, "HttpClient". Add a coded step to generate you .cs file. Delete everything in the namespace, you won't need it. Now, add your using directives (see previous section).
    The Class you need to make needs to allow the HttpClient to be created only once and read-only. It's a bit odd, so just copy+paste my code from the example. You will want to change the BaseAddress property of _client to suit your testing. Think of this property like the BaseURL project setting.
    Here is what my container class looks like:
    using Telerik.TestingFramework.Controls.KendoUI;
    using Telerik.WebAii.Controls.Html;
    using Telerik.WebAii.Controls.Xaml;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Linq;
     
    using ArtOfTest.Common.UnitTesting;
    using ArtOfTest.WebAii.Core;
    using ArtOfTest.WebAii.Controls.HtmlControls;
    using ArtOfTest.WebAii.Controls.HtmlControls.HtmlAsserts;
    using ArtOfTest.WebAii.Design;
    using ArtOfTest.WebAii.Design.Execution;
    using ArtOfTest.WebAii.ObjectModel;
    using ArtOfTest.WebAii.Silverlight;
    using ArtOfTest.WebAii.Silverlight.UI;
     
    using System.Net.Http;
    using System.Net.Http.Formatting;
     
    namespace TestRestAPI
    {
        public class RestClient
        {
            private static HttpClient _client = null;
     
            public static HttpClient client
            {
                get
                {
                    if (_client == null)
                    {
                        // Write action to console
                        Console.WriteLine("No active HttpClient, creating a new one.");
                         
                        // Create new Http Client Handler
                        HttpClientHandler handler = new HttpClientHandler
                        {
                            // Do not use a proxy
                            UseProxy = false
                        };
                         
                        // Create new Http Client using the Handler
                        _client = new HttpClient(handler);
                         
                        // Set BaseAddress
                        _client.BaseAddress = new Uri("http://httpbin.org/");
                         
                        // Write action to console
                        Console.WriteLine("Set Base Address to " + _client.BaseAddress.ToString());
                    }
                    return _client;
                 }
             }
        }
    }

    Create Your Test(s)
    Now that you have an HttpClient that can be used by multiple tests, you can call that client in your test(s). Create a web test and add a coded step, I like to delete all the #region code in the class as well as the giant comment block in the namespace. Also, I like to close the browser window that opens when a web test is ran, because it is not needed for REST test(s). To close the browser window, use the ActiveBrowser.Close(); function.

    Sending a GET
    In your test's class perform a get using GetAsync(). This takes a Uri parameter, which appends the BaseAddress to the value you pass in. In my example, comes out to "http://httpbin.org/get".
    Here is what my GET test looks like:
    using Telerik.TestingFramework.Controls.KendoUI;
    using Telerik.WebAii.Controls.Html;
    using Telerik.WebAii.Controls.Xaml;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Linq;
     
    using ArtOfTest.Common.UnitTesting;
    using ArtOfTest.WebAii.Core;
    using ArtOfTest.WebAii.Controls.HtmlControls;
    using ArtOfTest.WebAii.Controls.HtmlControls.HtmlAsserts;
    using ArtOfTest.WebAii.Design;
    using ArtOfTest.WebAii.Design.Execution;
    using ArtOfTest.WebAii.ObjectModel;
    using ArtOfTest.WebAii.Silverlight;
    using ArtOfTest.WebAii.Silverlight.UI;
     
    using System.Net.Http;
    using System.Net.Http.Formatting;
     
    namespace TestRestAPI
    {
        public class Get : BaseWebAiiTest
        {
            [CodedStep(@"GET")]
            public void Get_CodedStep()
            {
                // Close the web browser window (not needed)
                ActiveBrowser.Close();
                 
                // Write action to console
                Console.WriteLine("Sending GET...");
                 
                // Create and define the result of the GET. Note that GetAsync uses the BaseAddress set in the Module, "HttpClient"
                HttpResponseMessage result = RestClient.client.GetAsync("get").Result;
                 
                // Handle HttpClient Result
                if ((int) result.StatusCode == 200)
                {
                    // Response was OK
                    Console.WriteLine("Response == 'OK'");
                     
                    // Write result to log
                    Log.WriteLine(result.ToString());
                }
                else
                {
                    // Response was not expected
                    Console.WriteLine("Response != 'OK'");
                    throw new Exception(result.ToString());
                }
            }
        }
    }

    Sending a POST
    In your test's class perform a get using PostAsync(). This also takes the Uri parameter, but also requires an HttpContent parameter. What that parameter contains and it's format is completely up to your specific API. For my example, I know that httpbin.org uses JSON. So I made a simple JSON formatted object from a String Array. You will need to check what parameter your API takes from POST requests and of what type. This is expressed in my example in the HttpContent content = ... line.
    Here is what my example looks like:
    using Telerik.TestingFramework.Controls.KendoUI;
    using Telerik.WebAii.Controls.Html;
    using Telerik.WebAii.Controls.Xaml;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Linq;
     
    using ArtOfTest.Common.UnitTesting;
    using ArtOfTest.WebAii.Core;
    using ArtOfTest.WebAii.Controls.HtmlControls;
    using ArtOfTest.WebAii.Controls.HtmlControls.HtmlAsserts;
    using ArtOfTest.WebAii.Design;
    using ArtOfTest.WebAii.Design.Execution;
    using ArtOfTest.WebAii.ObjectModel;
    using ArtOfTest.WebAii.Silverlight;
    using ArtOfTest.WebAii.Silverlight.UI;
     
    using System.Net.Http;
    using System.Net.Http.Formatting;
     
    namespace TestRestAPI
    {
        public class Post : BaseWebAiiTest
        {
            [CodedStep(@"Post")]
            public void Post_CodedStep()
            {
                // Close the web browser window (not needed)
                ActiveBrowser.Close();
                 
                // Create the user login data
                String [] user = {"username", "password"};
                 
                // Create and define the HttpContent object to be passed in client.PostAsync function
                HttpContent content = new ObjectContent<String[]>(user, new JsonMediaTypeFormatter());
                 
                // Write action to console
                Console.WriteLine("Sending POST...");
                     
                // Create and define the result of the POST
                HttpResponseMessage result = RestClient.client.PostAsync("post", content).Result;
                 
                // Handle HttpClient Result
                if ((int) result.StatusCode == 200)
                {
                    // Response was OK
                    Console.WriteLine("Response == 'OK'");
                     
                    // Write result to log
                    Log.WriteLine(result.ToString());
                }
                else
                {
                    // Response was not expected
                    Console.WriteLine("Response != 'OK'");
                    throw new Exception(result.ToString());
                }
            }
        }
    }

    Test Validation
    The responses of the GET/POST/etc. are of type HttpResponseMessage, which liekly contain a JSON. You can convert the result to your object type and do asserts on those fields. Also, the get/post can return a 200 status code and have as empty JSON. Or, it can return a 409, 204, etc. Be sure to account for all expected outcomes or your test will break or pass when it ought to have been failed.
    I will use a made up data type called MyDataType to show an example:
    // Convert the result to your data type
    MyDataType getResult = result.Content.ReadAsAsync<MyDataType>().Result;
     
    // Handle the result as the object could be null and the http response code was a 200
    if (getResult.ResultEntries.Count() > 0)
    {
        //some action on the object, like...
        Log.WriteLine("Name: " + getResult.ResultEntries.ElementAt(0).Name.ToString());
    }
    else
    {
        // some action in response to the object being empty
    }

    Stay classy.
  2. Cody
    Admin
    Cody avatar
    3360 posts

    Posted 25 Nov 2013 Link to this post

    Hello Tim,

    Thank you for the code library. It is very well designed and written. We'll add it to our set of online code samples. I'm also granting you 10000 Telerik Points for such a well written article.

    Regards,
    Cody
    Telerik
    Quickly become an expert in Test Studio, check out our new training sessions!
    Test Studio Trainings
  3. Keith
    Keith avatar
    1 posts
    Member since:
    Jan 2014

    Posted 23 Jun 2014 Link to this post

    I'm happy to see someone implementing API testing through Test Studio.  I was not looking forward to maintaining multiple test apps for web testing. ;)
  4. Paul
    Paul avatar
    3 posts
    Member since:
    Oct 2013

    Posted 12 May 2015 Link to this post

    Hi Tim.

    Thanks for this it has been very useful. I have been looking at using this so the URI is set from BaseURL.

    This would be super handy as you could then change the environments when running from Test Lists, and set up groups of  regression tests across multiple environments.

     However I am having trouble setting the URI due to "(CS0120) An object reference is required for the non-static field, method, or property 'ArtOfTest.WebAii.Core.Manager.Settings.get'"

    I've tried various ways but basically, I want to change a line in the code to this ....

     _client.BaseAddress = new Uri(Manager.Settings.Web.BaseUrl);

    Any ideas of how this could be achieved would be greatly appreciated.

    Thanks again.

    Paul

  5. Paul
    Paul avatar
    3 posts
    Member since:
    Oct 2013

    Posted 12 May 2015 in reply to Paul Link to this post

    Hi Tim.

     

    I think I resolved this and it could be a useful enhancement to your post. 

    Very useful for setting up Scheduled Jobs and Test Script for regression tests over multiple environments. I was missing the correct place to make _baseurl Static.

     

        public class RestClient
        {
            private static string _baseurl;
            private static HttpClient _client = null;
            public static HttpClient client
            {
                get
                {
                    _baseurl = Manager.Current.Settings.Web.BaseUrl;
                    if (_client == null)
                    {
                        // Write action to console
                        Console.WriteLine("No active HttpClient, creating a new one.");
                        
                        // Create new Http Client Handler
                        HttpClientHandler handler = new HttpClientHandler{};
                   
                        // Create new Http Client using the Handler
                        _client = new HttpClient(handler);
                        
                        // Set BaseAddress
                        _client.BaseAddress = new Uri(_baseurl);
                        
                        // Write action to console
                        Console.WriteLine("Set Base Address to " + _client.BaseAddress.ToString());
                    }
                    return _client;
                 }
             }
        }

  6. Paul
    Paul avatar
    3 posts
    Member since:
    Oct 2013

    Posted 12 May 2015 in reply to Paul Link to this post

    Hi Tim.

    I was not making this static in the correct place. This would be a useful addition to your code as it means you can setup Test Lists and Scheduled Regression tests over multiple environments.

        public class RestClient
        {
            private static string _baseurl;
            private static HttpClient _client = null;
            public static HttpClient client
            {
                get
                {
                    _baseurl = Manager.Current.Settings.Web.BaseUrl;
                    if (_client == null)
                    {
                        // Write action to console
                        Console.WriteLine("No active HttpClient, creating a new one.");
                        
                        // Create new Http Client Handler
                        HttpClientHandler handler = new HttpClientHandler{};
                   
                        // Create new Http Client using the Handler
                        _client = new HttpClient(handler);
                        
                        // Set BaseAddress
                        _client.BaseAddress = new Uri(_baseurl);
                        
                        // Write action to console
                        Console.WriteLine("Set Base Address to " + _client.BaseAddress.ToString());
                    }
                    return _client;
                 }
             }
        }

  7. Tim
    Tim avatar
    5 posts
    Member since:
    Nov 2013

    Posted 15 May 2015 in reply to Paul Link to this post

    Paul,

    I am glad you figured out your issue. At the time I wrote the post I had not given consideration for multiple environments as I was only testing an API in our staging environment. Your addition is certainly helpful!

    Thanks,

    Tim

  8. Boyan Boev
    Admin
    Boyan Boev avatar
    1043 posts

    Posted 17 May 2015 Link to this post

    Hello Paul,

    Thank you for sharing this.

    We really appreciate this. I have updated your Telerik points.

    Regards,
    Boyan Boev
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  9. Jyoti
    Jyoti avatar
    3 posts
    Member since:
    Sep 2016

    Posted 07 Oct Link to this post

    Telerik Team,

    From past few weeks am working on your tool: Test Studio for APIs, there are so many things which are not clear in your document guide and webinar demo. This tool is new for me in terms of API testing. I would really appreciate if I can get some solutions on my following queries from your team with respect to this tool:

    1. Does Telerik Test Studio for APIs supports Web API testing?

    2. How do I pass the Web API URL to perform some GET and POST methods? (Should I simply add it as a base-url under Project?).

    3. While accessing some sample APIs like Google Maps (geocode) or Youtube API, it shows an Proxy Authorization issue status i.e. 407. This is blocking me from exploring the tool and its features.

    4. Your built-in demo application has no clear definition as to how it is connected with the tool. If I want to connect such .exe or console application with the tool, how should I proceed?

     

    Kindly help me with some solution as my organization is looking forward to use Test Studio API tool for future API projects.

Back to Top