Thursday, August 17, 2023

The Role of Latency, Throughput, and Response Time in Functional API Testing


Introduction

Functional testing aims to verify that an application's features and functions work as intended. This testing encompasses various scenarios to ensure that the application's functionalities meet the specified requirements. Incorporating metrics like latency, throughput, and response time into functional testing can provide a more comprehensive understanding of an API's performance.

Why Consider Performance Metrics in Functional Testing?

While functional testing primarily focuses on verifying the correctness of features, integrating performance metrics serves multiple purposes:

1. User Experience Validation: Ensuring that APIs respond within an acceptable time frame enhances the user experience, even during normal functional usage scenarios.

2. Load Impact: Functional testing can simulate different user loads. Measuring throughput helps assess how well an API handles varying levels of requests.

3. Identifying Hidden Issues: Slow response times or high latency may indicate inefficiencies or bottlenecks that might not be apparent during regular functional testing.

 

Applying Metrics in Functional Testing


1. Latency in Functional Testing: During functional testing, record the time taken for each API call's response. This helps verify whether an API's response time aligns with the expected requirements.


2. Throughput in Functional Testing: As part of functional testing, execute scenarios with different request loads. Assess whether the API maintains stable performance across varying loads.


3. Response Time in Functional Testing: Functional tests should include measurement of the complete time taken for an API request, from initiation to receiving the response. This provides insights into real-world performance.

 Integrating Performance and Functional Testing

1. Test Scenarios: Incorporate latency, throughput, and response time measurements into your existing functional test scenarios. Create scenarios that mimic realistic user behavior.

2. Test Data: Use diverse sets of test data to evaluate how different inputs affect performance metrics.

3. Assertions: Integrate performance assertions into functional tests. Define acceptable ranges for latency, throughput, and response time, and validate that they are met.

Conclusion

While functional testing ensures that an application's features work correctly, evaluating metrics like latency, throughput, and response time within this context provides a more holistic view. By incorporating these performance metrics, you can uncover potential issues, optimize user experiences, and validate the overall robustness of your APIs. Balancing both functional correctness and performance considerations ensures that your application not only works as intended but also performs well under different conditions.

Wednesday, October 12, 2022

API Load Testing with K6 & Postman

API Load Testing with K6 & Postman 




 We will explore how to use the postman collections to perform load testing using K6

Implementation

Pre-requisites 
  • Node js 
  • npm

Step 1:

Install k6 using the script 

npm install -g postman-to-k6



Step 2:

After installation of  k6 , next step is to export the postman collection 
 
postman-to-k6 collection.json -o demo.js

here collection.json is the  collection name 

This will help to convert the collection to javascript file like  this 

// Auto-generated by the postman-to-k6 converter

import './libs/shim/core.js';
export let options = { maxRedirects: 4};
const Request = Symbol.for("request");
postman[Symbol.for("initial")]({
  options
});

export default function() {
  postman[Request]({
    name: "Dummy GET call",
    id: "7e00f6d1-af40-4162-a4a7-42bacb37f163",
    method: "GET",
    address: "https://reqres.in/api/users?page=2",
    post(response) {
      pm.test("Successful response code 200.", function() {
        pm.response.to.have.status(200);
      });
    }
  });
}


In the options section of JavaScript code you can define the Duration of test and Users 

Final Script will be like this , here i have given duration for 1 minute and virtual user count is 50

// Auto-generated by the postman-to-k6 converter

import './libs/shim/core.js';
import { htmlReport } from "https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js";
export let options = { maxRedirects: 4,
  duration: '1m',
  vus: 50,
   };
const Request = Symbol.for("request");
postman[Symbol.for("initial")]({
  options
});

export default function() {
  postman[Request]({
    name: "Dummy GET call",
    id: "7e00f6d1-af40-4162-a4a7-42bacb37f163",
    method: "GET",
    address: "https://reqres.in/api/users?page=2",
    post(response) {
      pm.test("Successful response code 200.", function() {
        pm.response.to.have.status(200);
      });
    }
  });
}
export function handleSummary(data) {
  return {
    "summary.html": htmlReport(data),
  };
}

Step 3:

Execution and Reporting 


For executing you need to install k6 using  "winget install k6" command if you using windows package manager

Execute the script using the command 


k6 run demo.js


You will get the html report after execution like this 















That's it , Thanks 

Reference : https://k6.io/blog/load-testing-with-postman-collections/

Wednesday, May 25, 2022

Fetch Data from DB to CSV

 


Sometimes we will face scenarios to fetch data from database and need to store in csv , in this blog we are discussing on one of those scenarios .

We only need to write the SQL  query and the code is capable to fetch the column name and that will be the  header name in the CSV and the respective data inside the column will be added as different rows .

If the data is dynamic in the DB every time when you run the code the data in the csv will be deleted and newly added data will be replaced in the file.

C# Sample :  

       
        public void ExportDataToCSV()

        {

            string fileName = "DBTestData.csv";

            string fullFilepath = Path.Combine(Environment.CurrentDirectory, @"TestData\", fileName);

            string otherFileLocation = @"..\..\\..\\TestData\\" + fileName;

            string connectionString = "server = servername; uid = userid; pwd = password; database = dbname";

            string csvHeader = string.Empty;

            string csvData = string.Empty;


            using (SqlConnection con = new SqlConnection(connectionString))

            {

                using (SqlCommand cmd = new SqlCommand("SQL QUERY;"))

                {

                    using (SqlDataAdapter sda = new SqlDataAdapter())

                    {

                        cmd.Connection = con;

                        sda.SelectCommand = cmd;

 

                        using (DataTable dt = new DataTable())

                        {

                            sda.Fill(dt);

 
                            foreach (DataColumn column in dt.Columns)

                            {

                                //Add the Header row for CSV file.

                                csvHeader += column.ColumnName + ',';

                            }

                            //Add new line.

                            csvHeader += "\r\n";

 
                            File.WriteAllText(fullFilepath, csvHeader);

                            File.WriteAllText(otherFileLocation, csvHeader);

                            foreach (DataRow row in dt.Rows)

                            {

                                foreach (DataColumn column in dt.Columns)

                                {

                                    //Add the Data rows.

                                    csvData += row[column.ColumnName].ToString().Replace(",", ";") + ',';

                               }


                                //Add new line.

                                csvData += "\r\n";

                            }


                            //Setting the file Paths

                            File.AppendAllText(fullFilepath, csvData);

                            File.AppendAllText(otherFileLocation, csvData);

 
                        }

                    }

                }

            }

Friday, March 11, 2022

How to download file's using RestSharp , WebClient & RestAssured

 



Some times we need to perform file download operations using an api , in this blog we are going to deal different methods to download a file using 

1. WebClient

2. RestSharp

3.RestAssured


Code Sample for download operation using WebClient

using (WebClient client = new WebClient())
{
     #Give the API URI and path , file need to store
    client.DownloadFile("URI Path","FileDestinationPath");
}


Code Sample for download operation using RestSharp

#Initialize the restclient
var client = new RestClient("URI Path");

#save the file to the destination path
client.DownloadData(request).SaveAs(filePath);


Code Sample for download operation using RestAssured

@Test
	Public void fileDownloadTest() {

                #Extracting response into a byteArray
		byte[] dowloadedFile = RestAssured.given().when()
			.get("URI Path")
			.then().extract().asByteArray();

		try {
			FileOutputStream os = new FileOutputStream(new File("destinationPath"));
			os.write(dowloadedFile);
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
}

Tuesday, November 16, 2021

Find Broken Images in UI (Selenium & Rest Sharp )


Find Broken Images in UI



                




Broken image is a link/image that does not show up as a picture, clicking upon which takes the end-user to a defunct picture. The user encounters a 404 Error when clicked on the broken image
.

The code written to solve the issue using selenium and Rest sharp to interact with the broken links .


Code :

  • The details of the images present on the page are fetched by locating the WebElements with img tag
  • Using img.GetAttribute("src") we are fetching the URI and executing the URI using the Restsharp library to get the statuscode which is success or not found 


using OpenQA.Selenium;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Chrome;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using OpenQA.Selenium.Remote;
using System.Threading;
using System.Net.Http;
using System.Threading.Tasks;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;
using RestSharp;

namespace UI.TESTCASES.Helper

{

    public class BrokenImageFinder

    {

        // selenium Webdriver Initialization 

        IWebDriver driver;

        [Test]

        public async Task LT_Broken_Images_Test()

        {

            int broken_images = 0;

            String test_url = "https://the-internet.herokuapp.com/broken_images";

            // WebdriverManager Implementation that will download the respective chrome version  

            new DriverManager().SetUpDriver(new ChromeConfig());

            driver = new ChromeDriver();

            driver.Manage().Window.Maximize();

            driver.Navigate().GoToUrl(test_url);

            var image_list = driver.FindElements(By.TagName("img"));

            /* Loop through all the images */

            foreach (var img in image_list)

            {

                var img1 = img.GetAttribute("src");

                Thread.Sleep(3000);

                try

                {

                    RestClient client = new RestClient(img1);

                    RestRequest request = new RestRequest(Method.GET);

                    var response = client.Execute(request);

                    if (response.StatusCode == HttpStatusCode.OK)

                    {

                        Console.WriteLine("Image at the link " + img.GetAttribute("src") + " is OK, status is "

                                + response.StatusCode);

                    }

                    else

                    {

                        Console.WriteLine("Image at the link " + img.GetAttribute("src") + " is Broken, status is "

                            + response.StatusCode);

                        broken_images++;

                    }

                }

                catch (Exception ex)

                {

                    if ((ex is ArgumentNullException) ||

                       (ex is NotSupportedException))

                    {

                        System.Console.WriteLine("Exception occured\n");

                    }

                }

            }

            /* Perform wait to check the output */

            System.Threading.Thread.Sleep(2000);

            Console.WriteLine("\nThe page " + test_url + " has " + broken_images + " broken images");

        }

    }

}


Output : 





Tuesday, July 13, 2021

Create Self Hosted Agent for Azure Pipelines

  

1. Create an Account on Azure DevOps

Navigate to  the Url https://azure.microsoft.com/en-in/services/devops/ login with your Microsoft Account or create new one .



2. Create an Organization 

Click on New Organization give name for the Organization click continue 



3. Create a New Project

For creating a new project click on the New Projectgive the project name and select private or public depending on the requirement and click Create button. You can push the code to the created project repository !

4. Setting Up  Self Hosted Agent ( Personal computer / VM )

Go to Organization settings => Agent Pools => click on Add Pool ,you can setup the agent in the existing default pool also . select pool type as self -hosted 
give a name for the pool and click create button 




your pool will be listed with the existing pools with the given name .
 


 click on the pool => click New Agent => click Download the Agent 
create an Agent folder in the PC and extract the zip file in the Agent folder.


For setting up the agent you need  PAT ( Personal Access Token) , for that go to User Settings => click personal access token 



Enter the  details to generate the  token and store it some where 


Open PowerShell with administrator access and execute the command 

PS C:\WINDOWS\system32> cd C:\Agent
PS C:\Agent> .\config.cmd


1. you need to  give the Server URL : https://dev.azure.com/<ORGANISATION NAME>

2. Enter the   Personal Access Token

3. Enter  the  name of the agent pool that we created 

4. Enter a name for the agent 

5.  Give No  if you don't want to run it as a service .


Agent is created . You can double click run.cmd for  making it as online you can give the  name of Agent in the Yaml file or the classic editor for using it .

Example 

# ASP.NET Core (.NET Framework)
# Build and test ASP.NET Core projects targeting the full .NET Framework.
# Add steps that publish symbols, save build artifacts, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core

trigger:
- master

pool:  LocalPool


variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

steps:
- task: NuGetToolInstaller@1

- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'

- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

Friday, May 21, 2021

API Automation Using RestSharp [ Multipart/Form Data ]

 


Multipart/Form Data

A HTTP multipart request is a HTTP request that HTTP clients construct to send files and data over to a HTTP Server. It is commonly used by browsers and HTTP clients to upload files to the server.

Swagger Link : https://petstore.swagger.io/#/

Code :  

 [TestClass]
    public class DemoPostOperations
  {
    [Test]
        public void MultipartFormData()
        {
            var client = new RestClient("https://petstore.swagger.io/v2/");
            client.Authenticator = new HttpBasicAuthenticator("api_key", "****");
            var request = new RestRequest("pet/10/uploadImage", Method.POST);
            
            request.AddHeader("Content-Type", "multipart/form-data");
            request.AddHeader("Accept", "application/json");

            request.AddParameter("additionalMetadata", "abc123");
            request.AddFile("file", @"C:\Users\Admin\source\repos\WebserviceAutomation\WebserviceAutomation\Post Operations\Screenshot_1.jpg");

            IRestResponse response = client.Execute(request);
            var resonseContent = response.Content;

        }
 }


Response Body : 

{"code":200,"type":"unknown","message":"additionalMetadata: abc123\nFile uploaded to ./Screenshot_1.jpg, 18091 bytes"}

Sunday, May 2, 2021

API Automation Using HttpClient [GET Operation]

                  

 

HttpClient Class






Its a class for sending Http Request and receiving Http  Response from a resource identified by a URI 


Basic GET Operation using  httpclient 

[TestClass]
    public class Tests
    {
        private string getUrl = "https://reqres.in/api/users?page=2";
        [Test]
        public void TestMethod1()
        {

            // step 1. To  create http client 
            HttpClient httpClient = new HttpClient();

            //step for create the request and execute the request 
            Task<HttpResponseMessage> responseMessage = httpClient.GetAsync(getUrl);
            HttpResponseMessage httpResponseMessage = responseMessage.Result;
            Console.WriteLine(httpResponseMessage.ToString());

            //for printing the statusCode
            HttpStatusCode httpStatusCode = httpResponseMessage.StatusCode;
            Console.WriteLine("StatusCode=>{0}", httpStatusCode);
            Console.WriteLine("StatusCode=>{0}", (int)httpStatusCode);

            //for printing the content
            HttpContent httpContent = httpResponseMessage.Content;
            Task<string> ResponseContentData = httpContent.ReadAsStringAsync();
            string responseData = ResponseContentData.Result;

            Console.WriteLine(responseData);
            // step for closing the connection
            httpClient.Dispose();

        }
}

Monday, April 19, 2021

API Automation Using RestSharp [ Deserialization ]

 

How to Deserialize JSON Response to Class with RestSharp?


 The term Deserialization here means the conversion from the String form of JSON to a Class form. This is also called Object Representation of structured data.

  • Add Newtonsoft.json to the project via Nuget Package Manager => Manage Nuget packages for Solutions.
  • Create a model class of the json response like this

 public class Users
    {

        public string name { get; set; }
        public string job { get; set; }
        public string id { get; set; }
        public DateTime createdAt { get; set; }

    }
  • Make appropriate changes in the code like this
 public class DemoGetTest
    {
        private string BaseUrl = "https://reqres.in/";

        [Test]
        public void DeserializingJsonResponse()
        {
            var restClient = new RestClient(BaseUrl);
            var restRequest = new RestRequest("/api/users?page=2", Method.GET);
            restRequest.AddHeader("Accept", "application/json");
            IRestResponse response = restClient.Execute(restRequest);
            var content = response.Content;

            if (response.IsSuccessful)
            {
                Console.WriteLine("Status Code " + response.StatusCode);
                Console.WriteLine("Response Content " + response.Content);

            }

            //De-serialisation of Response Data 


            Root json = JsonConvert.DeserializeObject<Users>(content);
if(json.data[0].first_name== "Michael") { Console.WriteLine("operation passed "); } var jsonobject=JObject.Parse(content); int pagevalue =(int)jsonobject.GetValue("page"); } }

Monday, April 5, 2021

API Automation Using RestSharp Part II [ Method : GET ]

 

Uploading: 160221 of 160221 bytes uploaded.
How to Write GET API Test Using RestSharp?
  1. Create a test class DemoGetTest and test method Get Operations() in the project.
Operations to be  Performed : 
  • Create request from client and specify the HTTP Method type.
  • Send the Request to the Server.
  • Get the Response back from the server.
  • Validate returned Response’s Body.

Code Snippet :

 public class DemoGetTest
    {
        private string BaseUrl = "https://reqres.in/";

        [Test]
        public void GetOperationUsingRestSharp()
        {
            //Creating Client Connection
            IRestClient restClient = new RestClient(BaseUrl);

            //Creating Request from Client to Server
            IRestRequest restRequest = new RestRequest("/api/users?page=2", Method.GET);

            restRequest.AddHeader("Accept", "application/json");

            //Execute Request on Server
            IRestResponse response = restClient.Execute(restRequest);
            var content = response.Content;

            if (response.IsSuccessful)
            {
                Console.WriteLine("Status Code " + response.StatusCode);
                Console.WriteLine("Response Content " + response.Content);
                Console.WriteLine("Response Content " + response.Headers);
                //Console.WriteLine(restResponse.IsSuccessful);
                //Console.WriteLine(restResponse.StatusCode);
            }
            else
            {
                Console.WriteLine("Operation Failed");
                //Console.WriteLine(restResponse.ErrorMessage);
                //Console.WriteLine(restResponse.ErrorException); 
            }

            Assert.AreEqual(200, (int)response.StatusCode);

            //Verification of response
            if (!content.Contains("page"))
            {
                Assert.Fail("information is not displayed");
            }
        }
}