└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # API Testing Best Practices 2 | 3 | 4 | Welcome! Read This First 5 | 6 | ### What? 7 | This repository is a summary and curation of everything you need to know to write and perform effective API or service layer tests. 8 | 9 | ### Who? 10 | It is designed to suit developers and testers of all levels. The content is written in an easy-to-grasp manner suitable for beginner developers, while providing the most value to the reader regardless of their expertise. 11 | 12 | ### When? 13 | After laying a solid foundation in your application development process through comprehensive unit tests, you need to integrate all component and services. Use this repository as the fundamental guide for your API tests and service-level tests. 14 | 15 | ## Table of Contents 16 | - [1. What is an API?](#1-what-is-an-api) 17 | - [2. Overview of REST APIs](#2-overview-of-rest-apis) 18 | - [3. HTTP Methods used in APIs](#3-http-methods-used-in-apis) 19 | - [4. When should I use API tests?](#4-when-should-i-use-api-tests) 20 | - [5. What Should I Track About My APIs?](#5-What-Should-I-Track-About-My-APIs?) 21 | * [5.1 Request Headers](#51-request-headers) 22 | * [5.2 Authentication](#52-authentication) 23 | - [6. Best practices](#6-best-practices) 24 | * [6.1 Choose the Right API Testing Tool](#61-choose-the-right-api-testing-tool) 25 | * [6.2 Write clear tests that allow debugging](#62-write-clear-tests-that-allow-debugging) 26 | * [6.3 Start with API smoke testing](#63-start-with-api-smoke-testing) 27 | * [6.4 Test the performance of your API continuously](#64-test-the-performance-of-your-api-continuously) 28 | * [6.5 Simulate production conditions](#65-simulate-production-conditions) 29 | * [6.6 Take care of your testing parameters](#66-take-care-of-your-testing-parameters) 30 | * [6.7 API Mocking and Virtualization](#67-api-mocking-and-virtualization) 31 | * [6.8 Remove dependencies and fixed data sources whenever possible](#68-remove-dependencies-and-fixed-data-sources-whenever-possible) 32 | * [6.9 Include negative tests in your test suite](#69-include-negative-tests-in-your-test-suite) 33 | * [6.10 Content Extration](#610-content-extraction) 34 | * [6.11 Track All API Responses](#611-track-all-api-responses) 35 | * [6.12 Don't neglect security tests](#612-do-not-neglect-security-tests) 36 | * [6.13 Enforce Service Level Agreements (SLA)](#613-enforce-service-level-agreements) 37 | 38 | ## 1. What is an API? 39 | 40 | An [application programming interface](https://en.wikipedia.org/wiki/Application_programming_interface) (API) is a set of protocols that allow application software and their services to communicate with each other. APIs are essential when building and integrating software services because they allow the application to interact with external services. A good example is the [GitHub API](https://docs.github.com/en/rest). 41 | 42 | By allowing users to integrate new components and functionalities into existing architecture, APIs provide increased flexibility, simplicity, and opportunities for innovation when building applications. 43 | 44 | APIs also allow IT teams to collaborate and speed up the development and deployment process. For this reason, they have increasingly become the epicenter of today's cloud-native application development. 45 | 46 | ## 2. Overview of REST APIs 47 | 48 | The REST (REpresentational State Transfer) API design is a set of architectural constraints that every RESTful API must adhere to. RESTful APIs differ from SOAP APIs in that SOAP is a protocol while REST is simply an architectural style. 49 | 50 | As defined by Roy Fielding in his doctorate dissertation titled '[Architectural](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm) [Styles and the Design of Network-based Software Architectures](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm)', RESTful APIs must comply with the following six architectural principles: 51 | 52 | - **Based on the client-server architecture** 53 | A RESTful API should have an independent client and server. Their functions should be clearly delineated in that the UI and request-gathering are within the client's domain, while data access, security, and workload management are within the server's domain. All requests should be handled through HTTP 54 | - **Stateless operation**s 55 | All operations between the client and server should be stateless. At no point should the client content be stored on the server. Additionally, all session or state management information is held within the client-side. 56 | - **Cacheability** 57 | All resources should enable caching to minimize client-server interactions. The only exception is when caching is explicitly not possible. 58 | - **Layered system** 59 | Client-server interaction should work on an architecture with multiple server layers. This enables features like shared caches, load balancing, and security control. 60 | - **Uniform interface** 61 | Arguably the core of REST API design, this guideline defines four constraint facets. Resources should be identifiable through a single unique URL and should allow modification or manipulation through representations. Additionally, HTTP messages should be self-descriptive, and hypermedia should serve as the engine of application states. 62 | - **Code on demand** 63 | Servers often send back static information in the form of JSON or XML. However, they should extend their functionality to include the ability to share executable code to the client when necessary. 64 | 65 | ## 3. HTTP Methods used in APIs 66 | 67 | As you interact with the API, HTTP uses different methods to send requests and fetch data. Methods act as request _verbs_ because they tell the server what to do. 68 | 69 | Here's a peek into the most common HTTP methods used in APIs. 70 | 71 | > Note that the requests used are just examples. You should replace mywebsite.com with your domain name and provide a valid path as per your website/application directory. 72 | 73 | - **GET** 74 | Asks the server to retrieve information or a resource, without modifying it anyway. An example request would be HTTP GET 75 | - **POST** 76 | Used for creating a new subordinate resource in a collection of resources. For example, HTTP POST 77 | - **PUT** 78 | PUT requests asks the server to update or replace an existing resource. Unlike posts requests which are made on a resource collection, a PUT request is made on the resource. For instance, HTTP PUT 79 | - **DELETE** 80 | It is used for deleting resources specified in a URL. For example, HTTP DELETE 81 | - **PATCH** 82 | It is used for performing partial updates or modification of resources, but does not serve as a replacement for the PUT and POST methods. PATCH should only be used when updating an existing resource partially. 83 | 84 | Note that HTTP methods are case sensitive and should always be put in uppercase. 85 | 86 | When working with APIs, it is important to test whether your HTTP requests are working as desired in the API call. 87 | 88 | ## 4. When should I use API tests? 89 | An API is a critical application component. If it breaks or gets compromised, it puts the entire chain of processes built around it at risk. As such, end-to-end (e2e) API tests should be done after performing comprehensive unit tests covering individual functions. 90 | 91 | A good testing practice is to perform fewer tests as you get to higher levels. In line with Mike Cohn's [Test Pyramid concept](https://martinfowler.com/articles/practical-test-pyramid.html), API tests should be done at the service level (or integration). 92 | 93 | ![Test Pyramid](https://paper-attachments.dropbox.com/s_5F69C49EB0F27E6BA3986898C8AC84EAD54EB4A5AF7BA41D994FB78A5BD18F2F_1591870628660_test+pyramid.png) 94 | 95 | Because the API layer connects microservices to each other, or a client to the server, exhaustive API tests should be performed to ensure the following: 96 | - That the API implementation is working correctly 97 | - The implementation works as outlined in the requirements specification 98 | - There are no regressions between code/API merges and releases 99 | 100 | API tests aim to optimize performance and secure communication between different services. They provide higher reliability covering interfaces within the application logic but closer to the user (though not as UI tests). 101 | 102 | ## 5. What Should I Track About My APIs? 103 | There are a number of elements that you should analyze when testing APIs. These include: 104 | - Performance issues such as high API response time 105 | - Reliability issues such as difficulty in connecting or getting API responses 106 | - Structure of response data and its correctness 107 | - Missing or duplicate functionalities 108 | - Unused flags 109 | - Incorrect handling of arguments 110 | - Failure to handle error conditions 111 | - Improper warning or errors upon calling an API methods 112 | - Multi-threading issues 113 | - Security issues 114 | 115 | These are just some of the basic elements included in an API test suite. The goal when testing and monitoring API transactions is to validate every component and process involved in data exchange. 116 | 117 | Testing different parameters requires you to configure tests with request headers and authentication methods. 118 | 119 | ### 5.1 Headers 120 | The message header provides meta-information about a HPPT request or response. It also contains information about objects sent in the HTTP message body. 121 | All [HTTP headers](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields) have a generic format that consists of a name, colon, and then field values as shown: 122 | 123 | ``` 124 | message-header = field-name ":" [ field-value ] 125 | ``` 126 | 127 | There are four main types of message headers, namely: 128 | 129 | #### General Headers 130 | These are applicable for both client request and server response messages. These headers include: 131 | 132 | ``` 133 | general-header = Cache-Control 134 |               | Connection 135 |               | Date 136 |               | Transfer-Encoding 137 |               | Upgrade 138 |               | Pragma 139 |               | Trailer 140 |               | Via 141 |               | Warning 142 | ``` 143 | 144 | #### Request Headers 145 | 146 | They are used to modify the request message. Some popular request headers include: 147 | 148 | ``` 149 | request-header = Accept 150 |               | Accept-Charset 151 |               | Authorization 152 |               | Accept-Encoding 153 |               | Accept-Language 154 |               | Expect 155 |               | From 156 |               | Host 157 |               | If-Match 158 |               | If-Modified-Since 159 |               | If-None-Match 160 |               | If-Range 161 |               | If-Unmodified-Since 162 |               | Range 163 |               | Max-Forwards 164 |               | Proxy-Authorization 165 |               | Referer 166 |               | User-Agent 167 | ``` 168 | 169 | #### Response Headers 170 | They appear just below the response status line and contains a fairly limited set of entities as shown below. 171 | ``` 172 | response-header = Accept-Ranges 173 |               | Age 174 |               | Location 175 |               | ETag 176 |               | Proxy-Authenticate 177 |               | Server 178 |               | Vary 179 |               | Retry-After 180 |               | WWW-Authenticate 181 | ``` 182 | 183 | #### Entity Headers 184 | Entity headers provide meta-data about the content or mesage body. They include 185 | ``` 186 | entity-header = Allow 187 |             | Content-Language 188 |             | Content-Encoding 189 |             | Content-Location 190 |             | Content-Length 191 |             | Content-Type 192 |             | Content-MD5 193 |             | Content-Range 194 |             | Expires 195 |             | Last-Modified 196 | ``` 197 | 198 | The HTTP protocol also treats custom headers created and sent by clients as entity headers. 199 | 200 | When testing the API, it is important to simulate the real-world transaction by including the request headers that make up the API call. In the request header, you can specify whether the HTTP request is a GET or POST, and if it requires any form of authentication or data caching during the session. 201 | 202 | Typically, users execute a series of actions that can be viewed as flows. For instance, the sign-up flow, the login flow, or the export data flow. 203 | 204 | When testing an API, verify that these HTTP requests execute successfully, and that users receive the correct response. This can be achieved by examining the request headers, status line, and message body. 205 | 206 | An effective approach would be using [Loadmill](https://www.loadmill.io/) to test different methods using different parameters in the API test flow as shown below. 207 | 208 | ![Loadmill API Test](https://paper-attachments.dropbox.com/s_5F69C49EB0F27E6BA3986898C8AC84EAD54EB4A5AF7BA41D994FB78A5BD18F2F_1591938846318_LOADMILL+API+TEST.png) 209 | 210 | After running the API test, Loadmill returns detailed information showing the results for all HTTP requests in the test case. 211 | 212 | ![Loadmill Response](https://paper-attachments.dropbox.com/s_5F69C49EB0F27E6BA3986898C8AC84EAD54EB4A5AF7BA41D994FB78A5BD18F2F_1591938894268_RESPONSE.png) 213 | 214 | A section of the results also shows the HTTP request header: 215 | 216 | ![Loadmill Response](https://paper-attachments.dropbox.com/s_5F69C49EB0F27E6BA3986898C8AC84EAD54EB4A5AF7BA41D994FB78A5BD18F2F_1591938985297_LOADMILL+RESPONSE.png) 217 | 218 | ### 5.2 Authentication 219 | Almost every REST API requires users to pass some sort of authentication process. Authentication is when a user or any other entity proves their identity during a connection attempt. 220 | 221 | Simulating API transactions in a test would therefore involve testing the supported authentication methods. The three most common authentication methods used in REST APIs are basic authentication, API keys, and OAuth. 222 | 223 | #### Basic Authentication 224 | Users send their username or account ID and password in every API call. Here is an example: 225 | 226 | ```sh 227 | curl "https://samplewesb1.com/" \ 228 | -H "Authorization: Basic dyaXNlcm5hbWU6cGFzc3dvcmQ 229 | ``` 230 | 231 | The string basic shows that we are using the basic access authentication method while the string *dyaXNlcm5hbWU6cGFzc3dvcmQ=* represents a base64-encoding of username: password. 232 | 233 | #### Cookie-Based Authentication 234 | In cookie-based authentication, a user enters their credentials and the server verifies that they are correct. Upon verification, it creates a new session for the user. 235 | 236 | ```json 237 | { 238 | "session": 239 | { 240 | "name":"example.cookie.name", 241 | "value":"6E244567o899EFTBO87XI567896704A9EB4AE501F" 242 | } 243 | } 244 | ``` 245 | 246 | It then  places a cookie with the session ID in their browser. 247 | 248 | ```http 249 | Set-Cookie: example.cookie.name=6E244567o899EFTBO87XI567896704A9EB4AE501F; Path=/; HttpOnly 250 | ``` 251 | 252 | For all subsequent requests to the API, the session ID is checked and if valid, the use request is processes. Upon logging out, the session is destroyed on both the server-side and client-side. 253 | 254 | #### API Keys 255 | The API service generates a unique key for every account, which users must provide alongside their requests. 256 | The API key is a long, unguessable secret string that the API creates and gives to the user. Its something like: 257 | 258 | ``` 259 | t34580942sf4e0b742e66434hasdr0a5ed75f0bjkdbe 260 | ``` 261 | 262 | There is no standard [implementation for API keys](https://www.freecodecamp.org/news/best-practices-for-building-api-keys-97c26eabfea9/), but they are often passed alongside the API authorization header. 263 | 264 | ```sh 265 | curl "https://example.com/" \ 266 | -H "Authorization: t34580942sf4e0b742e66434hasdr0a5ed75f0bjkdbe 267 | ``` 268 | 269 | #### OAuth 270 | Technically, [OAuth](https://auth0.com/docs/protocols/oauth2) is not only an authentication method but also for _authorization_ purposes. 271 | 272 | When a user hits the sign-in button, the system sends an authentication request in the form of an access token. The user then forwards the request to an authentication server, which grants permissions or rejects the request. 273 | 274 | The access token is then provided to the user and the API provider and can be checked from time to time. However, the token is only valid for a limited period. 275 | 276 | When working with REST APIs, remember that OAuth and Basic authentication methods should never be implemented on plain HTTP. Instead, protect them through SSL/TLS. 277 | 278 | ## 6. Best practices 279 | 280 | This section delves into the best practices every tester should follow to write and perform effective API tests. 281 | 282 | ### 6.1 Choose the Right API Testing Tool 283 | Like any other kind of testing, the choice of tool or automation framework used has a substantial impact on the effectiveness and success of your testing efforts. Using a solid API test automation tool brings a wide range of benefits to the testing process, including higher accuracy, reusability, and scalability of tests. 284 | 285 | The ideal automation testing tool facilitates smooth measuring, tracking, and testing of the API functionality and performance. Since most allow developers to create complex multi-step testing scenarios, you can easily modify existing test cases or add new tests as the testing requirements change. This is especially important because, as most applications scale, the scope of testing also increases. 286 | 287 | Worth a mention is that you should not use tools UI testing tools to test your API. For the best results, consider using a tool that is specially designed for API testing. Using a great API test tool enhances test development, maintainability, and execution. 288 | 289 | ### 6.2 Write clear tests that allow debugging 290 | There are a number of reasons that lead to failures when performing API tests, most notably: 291 | - Flawed test automation 292 | - Inclusion of race conditions in the test 293 | - Flawed API functionality 294 | - Unstable application functionality 295 | - Implementing changes in the application without modifying the test 296 | - Environment failure 297 | 298 | When writing API tests, give every test case the attention-to-detail it deserves. It is always a good idea to test components separately for all possible configurations. 299 | 300 | To simplify the process of debugging, ensure the failure clause of your test is clearly shown in the test report, including detailed descriptive information. This way, it will be easier to run successful test cases, and in case of a failure, you can easily track the underlying cause. 301 | 302 | ### 6.3 Start with API smoke testing 303 | Every time you put up a new API for testing, always start by performing a smoke test. This is a quick test done to validate the API code and confirm that the basic and critical functionalities are working. 304 | 305 | A typical smoke test calls the API to verify whether it responds. It also calls the REST API using a standard amount of test data, followed by a larger amount of data to check whether it responds correctly. 306 | 307 | - **[Smoke testing](http://softwaretestingfundamentals.com/smoke-testing/)** the API also involves verifying whether the API interacts with other application components as well as APIs as desired. 308 | - **Sanity testing** should also be done at the beginning to ensure that the results of your smoke tests make sense in the context of the designated API function or purpose. In a sanity test, you verify whether the API interprets and displays the correct data as expected. 309 | - **[Smoke testing and sanity testing](https://www.guru99.com/smoke-sanity-testing.html)** aims to identify major flaws in a build and provide an immediate resolution before performing the full test. While serving as a great starting point of the testing process, these tests help reduce the amount of time spent in API testing. 310 | 311 | ### 6.4 Test the performance of your API continuously  312 | Testing the availability of an API is not enough. You need to test the performance and ensure it can support the desired load without outages or degradation of service. Ideally, you should check: 313 | - The number of concurrent server connections it can take before failure 314 | - Concurrent user load in batches of 10, 50, 100, 200, 500, and so on. 315 | - The expected throughput and response time for different user loads. 316 | - The maximum queries or number of calls executed per second. 317 | 318 | Continuously testing the API helps you identify performance issues to ensure there are no failures, or speed issues when the application is released to end-users. 319 | 320 | ### 6.5 Simulate production conditions 321 | When testing an API, it is important to simulate the conditions it will encounter when released for public use. By doing so, you ensure that the test results reflect the accurate (or near-accurate) functionality and performance of the API in is intended production environment. 322 | 323 | Treating the API like it is in the consumer environment also gives a clue on performance issues that the development team needs to resolve before moving forward. After all, most things tend to break in unpredictable ways when released to a live environment. 324 | 325 | ### 6.6 Take care of your testing parameters  326 | An API consists of multiple methods and operations, which should be tested individually and collectively by combining multiple API calls. For comprehensive testing, it is always a good idea to list all the mandatory parameters in your API call/request. 327 | 328 | Here are some simple steps you can follow to cover different parameters options and variations that are used by your users. 329 | - Map out the initial conditions required for API testing 330 | - Identify all parameters required and choose values for each 331 | - Identify all possible parameter combinations 332 | - Decide the most appropriate order for calling your API so it exhibits real-world functionality. 333 | - Observe the response/output 334 | 335 | Following these steps ensures you do not miss out on some critical parameters required in the request and JSON response. Additionally, perform data-type tests on individual methods or operations to ensure they align with the parameters defined. 336 | 337 | ### 6.7 API Mocking and Virtualization 338 | API testing usually involves testing many other interconnected components in an application. However, there are times that some components required for complete API testing may not be available dues to some unavoidable reasons. 339 | 340 | For instance, the component may not be developed yet. Another scenario is when the component holds unusable or insufficient test data. Alternatively, the component might be ready, but it is shared with other teams, so testers cannot use it freely. 341 | 342 | When you encounter any of the above scenarios during testing, virtualization is the most viable solution to enable continuous testing of the API as planned. 343 | 344 | Virtualization in API testing takes various forms, including: 345 | - **[Virtualization](https://en.wikipedia.org/wiki/Service_virtualization)** 346 | It involves simulating the behavior of complex application components such as database connectivity at the back-end or transport layer protocols (but not HTTP). 347 | - **[Stubbing](https://en.wikipedia.org/wiki/Method_stub#:~:text=A%20method%20stub%20or%20simply,to%2Dbe%2Ddeveloped%20code.)** 348 | Stubbing is used for creating an emulation of a SOAP or REST web service API. 349 | - **[Mocking](https://en.wikipedia.org/wiki/Mock_object)** 350 | It involves creating mock code objects with the help of frameworks such as Mockito. Another useful framework for mocking API requests and responses is [Polly.JS](https://netflix.github.io/pollyjs/#/), which allows users to record, replay, and stub HTTP interactions. 351 | 352 | ### 6.8 Remove dependencies and fixed data sources whenever possible 353 | API endpoints in a live environment usually rely on internal application components and external elements such as other APIs, third-party services, servers, legacy systems, and so on. When performing API tests, you’ll also have to deal with input from these dependencies. 354 | 355 | The best approach is usually eliminating these dependencies and fixed data sources whenever possible. When you test some API’s with static data collected from other sources, you’re not testing the API holistically. 356 | 357 | Instead, you should do away with these dependencies and follow actual user flows. This makes your API tests complete and more efficient. 358 | 359 | ### 6.9 Include negative tests in your test suite 360 | It is normal to perform positive tests in any scenario. For instance, inputting valid data and verifying whether an API request is processed correctly. Although this is the standard way of testing, it is important to verify the results with negative tests. 361 | 362 | Performing negative tests with equal due diligence makes it easier for testers to identify whether the API deals with receiving invalid or incorrect data gracefully. 363 | 364 | The expected response in such a negative test is that the API should provide an error message, but not encounter a hard crash or complete stop. 365 | 366 | Negative tests help verify the completeness of the application as well as its ability to accommodate user error. 367 | 368 | 369 | ### 6.10 Content extraction 370 | Content extraction is the process of parsing and extracting content from the response data. Extraction is particularly helpful when you need to generate dynamic content for subsequent requests, for instance, cookie values or access tokens. 371 | 372 | When extracting content from HTTP responses, you must set the extraction feature the request options parameter. The steps involved are: 373 | - State the desired type. This could be xpath, jsonpath, header, etc. 374 | - Specify the reference names 375 | - Specify the expressions 376 | 377 | Note that you can use multiple content extractions in a single request. 378 | 379 | Here is an example: 380 | ```js 381 | session.get("/tokens", {` 382 |   extraction: {` 383 |     jsonpath: {` 384 |       "accessToken": "authorization.token",` 385 |       "checksum": "authorization.checksum"` 386 |     }` 387 |   }` 388 | }); 389 | ``` 390 | 391 | The getVar() function can help us use extracted content in subsequent requests: 392 | 393 | ```js 394 | session.get("/ping?token=" + session.getVar("accessToken")); 395 | ``` 396 | 397 | Here is another example extraction using Xpath, a method to extract information from an XML document. Given the response and request options below: 398 | 399 | ```xml 400 | 401 | 402 | 403 | 404 | Martin 405 | Luther King 406 | martinLking@sampleweb1.com 407 | 408 | 409 | ``` 410 | 411 | ```js 412 | // This is the response extraction 413 | session.get("/tokens", { 414 | extraction: { 415 | xpath: { 416 | "email": "/users/user[1]/email" 417 | } 418 | } 419 | });  420 | ``` 421 | 422 | This makes the email a dynamic data source available within the same session. 423 | 424 | ```js 425 | session.put("/user?email=" + session.getVar("email")); 426 | ``` 427 | 428 | 6.11 Track All API Responses 429 | API responses are some of the most critical elements that you should track and record during the development process. However, the vast majority of developers and testers tend to discard these responses. 430 | 431 | It is vital to track API responses because they provide a benchmark of how it worked during a particular build at the time of testing. 432 | 433 | Responses are preserved so that, when the API undergoes a series of changes, it will be easier to examine responses from preceding builds in future. When an error occurs, it will be easier to figure out the modification leading to an error. 434 | 435 | During testing, calling the API is not enough. You must assert that the response and values returned are correct. This involves: 436 | - Validating the HTTP status code -- Verify that the status code returned is correct for each request. For instance, check whether unpermitted requests return 403 FORBIDDEN. 437 | - Verifying response payload- It involves checking whether the JSON body is valid including correct data types, field names, and values. 438 | - Verifying response headers, correct application state, and basic performance sanity. 439 | 440 | ### 6.12 Do not neglect security tests 441 | Cyber threats such as data breaches are increasing at an exponential rate in today's highly interconnected world. Every year, thousands of organizations and businesses say their applications (and application data) have been compromised. 442 | 443 | A poorly implemented API is one of the most common loopholes that attackers can exploit. 444 | 445 | Part of the API testing process should, therefore, focus on testing the security features of the API. When testing, ensure you verify that the API authentication works effectively and that data exchange between components is secure. 446 | 447 | API methods, if not implemented correctly, also allow third parties to compromise the application. You should, therefore, test all methods to ensure they do not provide a loophole for compromise when making an API call. 448 | 449 | ### 6.13 Enforce Service Level Agreements 450 | The API testing process should also focus on proper enforcement of service-level-agreements (SLAs), especially when the API is fully functional and awaits release. This helps testers check the performance issues underlying an API. 451 | 452 | The quicker you identify these issues, the easier it will be to fix them and avoid breaching SLAs when the application is released. 453 | 454 | API testing is an integral element of the application development, and should always be done holistically to ensure a polished final product. For the best results, keep the above testing practices in mind. 455 | --------------------------------------------------------------------------------