
Introduction
In today’s fast-paced software development landscape, ensuring the reliability of web services is more important than ever. API automation testing is crucial in streamlining this process by reducing manual effort, improving efficiency, and catching defects early in the development cycle.
In this article, we’ll walk you through the process of setting up API automation using xUnit and RestSharp. You will have a firm grasp on how to write dependable and effective tests for your web services by the end.
What is API testing?
API testing is a software validation method that focuses on directly examining application programming interfaces (APIs) and their integration to ensure they adhere to expected standards of functionality, reliability, performance, and security. API testing occurs at the message layer, as APIs lack a graphical user interface, enabling efficient and effective verification of the application’s logic.
This type of testing is crucial for automated testing and CI/CD processes because it can keep up with rapid release schedules and regular changes, especially in the user interface, without compromising test outcomes. Furthermore, API testing demands a lower maintenance effort compared to UI automation testing, making it a favored option for teams employing Agile and DevOps methodologies.

What is API automation?
As API testing becomes increasingly important in software development cycles and the number of test cases per API endpoint increases, the time required to validate all the possible scenarios manually becomes too much. This is where automation comes in. By automating all the test cases for a particular API, we can ensure that testing is completed on time while improving accuracy and efficiency.
Advantages of API automation:
- Language Independence: API testing allows for language-agnostic automation, as data exchange via XML and JSON is independent of the languages used in application development. These formats are structured and supported by built-in libraries, facilitating quick and stable data verification.
- Early Testing: Performing API testing before GUI testing enables early detection of defects. This accelerates feedback and enhances productivity by allowing teams to address issues before the GUI phase.
- Enhanced Test Coverage: APIs typically have detailed specifications that help in creating comprehensive automated tests. This includes various functional tests (like positive and negative scenarios) as well as non-functional testing. The automation of these tests is often feasible due to virtual user techniques, which enhance overall test coverage.
- Speedier Releases: API testing is significantly faster than GUI testing, with API scenarios often completed in 1–2 hours compared to 8–10 hours for UI regression tests. The lower susceptibility to errors in API testing also contributes to quicker releases.
- Reduced Flakiness: Unlike UI testing, which is prone to inconsistencies due to interface dependencies, API testing offers a more stable and reliable test environment. This stability reduces the time spent fixing flaky tests and debugging erratic behaviors, leading to more dependable automation results.
XUnit
xUnit refers to a family of unit testing frameworks that follow a common pattern and are derived from the original Smalltalk testing framework known as SUnit. These frameworks are available for various programming languages, with some of the most popular being JUnit for Java, NUnit for .NET, and PHPUnit for PHP. They provide a standardized way to write and run tests, making them highly effective for test-driven development (TDD).
Why XUnit Is Used for API Automation:
- Standardized Testing Structure: XUnit frameworks provide a systematic approach to constructing tests, encompassing setup, teardown, test cases, and assertions. This framework is especially beneficial for API testing, enabling developers to establish consistent and repeatable test cases that clearly define expected results.
- Automated Test Discovery and Execution: XUnit frameworks automatically recognize test methods based on attributes or naming conventions, making it easier to manage and execute large suites of tests. This is ideal for API automation where numerous endpoints and functionalities need to be tested regularly.
- Integration with CI/CD Pipelines: Tests developed using XUnit can be incorporated into CI/CD pipelines such as Bitbucket or GitLab during the development phases. This integration aids in identifying errors early in the development process.
- Rich Assertion Libraries: XUnit frameworks come with extensive assertion libraries that make it easier to verify complex API responses. They can handle various response formats and content types, making them versatile for API testing.
RestSharp:
RestSharp is a versatile library designed for making both synchronous and asynchronous HTTP calls, primarily tailored for developers dealing with REST APIs but capable of handling any HTTP-based interactions compliant with W3C standards. It simplifies handling various HTTP requests and responses in .NET by enabling the construction of valid request URIs with diverse parameters, including path, query, form, or body.
Choosing RestSharp over the built-in HTTP methods in .NET offers advantages like streamlined request and response management and a reduction in boilerplate code, making it ideal for complex applications that require detailed HTTP request configurations. This ease of managing different parameter types with RestSharp enhances its utility in more sophisticated settings.
Project Setup
- Open Visual Studio.
- Click New.
3. Under Web and Console, select Tests.
- Select the target framework.
- Enter the project name and click Create.
Your first XUnit project will be created.
- Install RestSharp.
Go to Project -> Manage NuGet Packages.
Search for RestSharp, select the package, and click Add Package.
The RestSharp package will be added to the project.
Folder Structure:
Config:
Constants.cs:
This file has the constant values used throughout the project.
IntegrationConfiguration.cs:
This contains the endpoint details for the APIs.
SharedMethods.cs:
This contains methods for making HTTP requests to the APIs and other methods, like error handling.
Models:
The folder contains model classes for both the request and response bodies utilized by the API.
Example:
LoginRequest.cs
LoginResponse.cs
Integration.Tests:
This folder contains the tests for the APIs.
Example:
AssertionMethodsDemo.cs
Automating a GET request:
We will be automating the GET request below.
https://api.agify.io/?name=michael&country_id=US
Response:
{
"count": 230,
"name": "michael",
"age": 58,
"country_id": "NZ"
}
WhenAgeIsRequested.cs
using Xunit;
using RestSharp;
using IntegrationTestDemo.Models;
using IntegrationTestDemo.Config;
using System.Text.Json;
namespace Integration.Tests
{
public class WhenAgeIsRequested
{
[Fact]
public void ShouldReturnAge()
{
//Construct request query parameters
Dictionary<string, string> queryParams = new Dictionary<string, string> { { "name", Constants.testName }, { "country_id", Constants.testCountryCode } };
//send GET request
RestResponse restResponse = SharedMethods.BasicGetCall(queryParams, "age");
//Deserialize response
AgeResponse ageResponse = JsonSerializer.Deserialize(restResponse.Content);
//validate 200 response code
Assert.True(200 == (int)restResponse.StatusCode, SharedMethods.ApiFailureMessage(restResponse));
//validate response for correct values
Assert.Equal(Constants.testName, ageResponse?.Name);
Assert.Equal(Constants.age, ageResponse?.Age);
Assert.Equal(Constants.count, ageResponse.Count);
Assert.Equal(Constants.testCountryCode, ageResponse.CountryId);
}
}
}
public static RestResponse BasicGetCall(Dictionary<string, string> queryParameters, string service)
{
RestClient client = new RestClient(GetService(service));
RestRequest request = new RestRequest();
// Construct the query params
foreach (KeyValuePair<string, string> parameter in queryParameters)
{
request.AddParameter(parameter.Key, parameter.Value);
}
// Make the request and get response
request.RequestFormat = DataFormat.Json;
RestResponse response = client.ExecuteGetAsync(request).Result;
return response;
}
/// <summary>
/// Get the correct service to compose the test url
/// </summary>
/// <param name="service">string used to determine the url to construct</param>
/// <returns></returns>
public static string GetService(string service)
{
string serviceUrl;
switch (service)
{
case "age":
serviceUrl = IntegrationConfiguration.AgeApiEnvUrl;
break;
case "login":
serviceUrl = IntegrationConfiguration.LoginApiEnvUrl;
break;
default:
throw new Exception($"Service '{service}' is not recognized");
}
return serviceUrl;
}
Automating a POST request:
https://reqres.in/api/login POST
Request body:
{
"email": "eve.holt@reqres.in",
"password": "cityslicka"
}
Response:
{
"token": "QpwL5tke4Pnpja7X4"
}
WhenLoginIsRequested.cs:
using Xunit;
using RestSharp;
using IntegrationTestDemo.Models;
using IntegrationTestDemo.Config;
using System.Text.Json;
using Xunit.Abstractions;
namespace Integration.Tests
{
public class WhenLoginIsRequested
{
//set up TestOutputHelper for debugging
private readonly ITestOutputHelper _testOutputHelper;
public WhenLoginIsRequested(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}
[Fact]
public void ShouldLoginSuccessfullyForValidCredentials()
{
//construct login request
LoginRequest loginRequest = new LoginRequest()
{
Email = Constants.testEmail,
Password = Constants.password
};
string jsonRequest = JsonSerializer.Serialize(loginRequest);
//send POST request
RestResponse restResponse = SharedMethods.BasicPostCall("login", "login", jsonRequest);
//validate 200 status code
Assert.True(200 == (int)restResponse?.StatusCode, SharedMethods.ApiFailureMessage(restResponse));
LoginResponse loginResponse = JsonSerializer.Deserialize(restResponse.Content);
//validate response for correct values
Assert.Equal(Constants.token, loginResponse.Token);
Assert.NotEmpty(loginResponse.Token);
Assert.IsType(loginResponse.Token);
}
}
}
public static RestResponse BasicPostCall(
string route,
string service,
string requestObj
)
{
RestClient client = new RestClient(SharedMethods.GetService(service));
RestRequest request = new RestRequest(route, Method.Post);
request.AddStringBody(requestObj, DataFormat.Json);
// Send POST request
RestResponse restResponse = client.ExecutePostAsync(request).Result;
return restResponse;
}
Running the tests in the CI/CD pipeline:
The automated API tests were created using xUnit and RestSharp and integrated into the Bitbucket pipeline. These tests are executed as part of the CI/CD pipeline during the application deployment step. This ensures that the tests run whenever code is pushed from one stage to another, verifying that new changes do not disrupt the existing workflow.
Creating a pipeline using Bitbucket:
In the repository, click ‘Pipelines’ -> Create your first pipeline.
Select the ‘Starter’ pipeline.
Enter the code provided below into the bitbucket-pipelines.yml file and then click on ‘Commit file’.
definitions:
steps:
- step: &Integration-tests
name: Integration tests
image: mcr.microsoft.com/dotnet/sdk:7.0
script:
- dotnet test
pipelines:
default:
- step: *Integration-tests
Running the automated tests in the Bitbucket pipeline:
Once the pipeline is configured and the test code is pushed to the repository, the tests can be executed in the pipeline. To run the tests, click Pipelines->Run Pipeline
Select the branch and the pipeline. We have only one pipeline, so we select the default one. Click Run.
We will execute the tests and display the results.
Conclusion:
Automating API tests using xUnit and RestSharp improves efficiency and ensures that web services remain reliable and functional throughout the development lifecycle. With a well-structured test suite, teams can catch potential issues early, streamline debugging, and maintain code quality with confidence. By integrating these tools into your workflow, you can create a scalable, maintainable, and effective testing strategy that enhances overall software stability and performance.
Repository link:
https://bitbucket.org/hvpk95/integration-test-xunit/src/integration-test/
References:
https://xunit.net/#documentation
https://restsharp.dev/docs/intro
https://www.atlassian.com/software/bitbucket/features/pipelines