mirror of
https://github.com/hmalik144/api-testing-automation-framework.git
synced 2025-12-10 02:55:21 +00:00
readme.md added
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -36,3 +36,9 @@ build/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
|
||||
### dot env ###
|
||||
.env
|
||||
|
||||
### report results ###
|
||||
app-info.html
|
||||
19
LICENSE.md
Normal file
19
LICENSE.md
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2024
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
37
pom.xml
37
pom.xml
@@ -85,13 +85,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
@@ -100,12 +94,6 @@
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
<!-- jUnit -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
@@ -129,11 +117,11 @@
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
<version>4.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>api-testing-automation-framework</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.example</groupId>-->
|
||||
<!-- <artifactId>api-testing-automation-framework</artifactId>-->
|
||||
<!-- <version>1.0-SNAPSHOT</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-coroutines-core</artifactId>
|
||||
@@ -157,9 +145,16 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.jasperreports</groupId>
|
||||
<artifactId>jasperreports</artifactId>
|
||||
<version>6.20.0</version>
|
||||
<groupId>io.github.cdimascio</groupId>
|
||||
<artifactId>dotenv-kotlin</artifactId>
|
||||
<version>6.4.1</version>
|
||||
</dependency>
|
||||
<!-- https://maven.apache.org/surefire/maven-surefire-plugin/dependency-info.html -->
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M7</version>
|
||||
<type>maven-plugin</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
98
readme.md
Normal file
98
readme.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Automation API Testing Framework
|
||||
|
||||
This repository contains an Automation API Testing Framework built with Kotlin and Maven. The framework is designed to provide a robust, scalable, and maintainable structure for automated testing of RESTful APIs.
|
||||
|
||||
## Table of Contents
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation](#installation)
|
||||
- [Project Structure](#project-structure)
|
||||
- [Configuration](#configuration)
|
||||
- [Prerequisites for Testing](#prerequisites-for-testing)
|
||||
- [Running Tests](#running-tests)
|
||||
- [Reporting](#reporting)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## Prerequisites
|
||||
Before you begin, ensure you have met the following requirements:
|
||||
- You have installed [JDK 17](https://www.oracle.com/java/technologies/downloads/#java17) or later.
|
||||
- You have installed [Maven](https://maven.apache.org/install.html).
|
||||
- You have installed [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
|
||||
- IDE capable of running Kotlin. eg. Intellij, Eclipse (requires kotlin plugin), VS Studio (requires kotlin plugin) [although it is possible to run from the command line]
|
||||
|
||||
## Installation
|
||||
1. Clone the repository:
|
||||
```sh
|
||||
git clone https://github.com/your-username/automation-api-testing-framework.git
|
||||
```
|
||||
2. Navigate to the project directory:
|
||||
```sh
|
||||
cd automation-api-testing-framework
|
||||
```
|
||||
3. Install the dependencies:
|
||||
```sh
|
||||
mvn -DskipTests=true package
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
The framework follows a standard Maven project structure:
|
||||
```
|
||||
automation-api-testing-framework
|
||||
├── src
|
||||
│ ├── main
|
||||
│ │ └── kotlin
|
||||
│ │ └── org
|
||||
│ │ └── example
|
||||
│ │ ├── api
|
||||
│ │ ├── model
|
||||
│ │ ├── storage
|
||||
│ ├── test
|
||||
│ │ └── kotlin
|
||||
│ │ └── org
|
||||
│ │ └── example
|
||||
│ │ ├── utils
|
||||
│ │ ├── ...
|
||||
├── pom.xml
|
||||
└── README.md
|
||||
```
|
||||
|
||||
- `api`: Api which is to be tested.
|
||||
- `model`: data classes of the responses and requests for api.
|
||||
- `storage`: caching class for storing api data.
|
||||
- `utils`: Helper functions and utilities.
|
||||
|
||||
## Configuration
|
||||
Configuration files are located in the `src/main/kotlin/com/yourpackage/config` directory. Modify the configuration files as per your testing environment.
|
||||
|
||||
## Prerequisites for Testing
|
||||
### Create a .env File
|
||||
In the root directory of your project, create a file named .env. This file will hold all your environment-specific variables. For example:
|
||||
```env
|
||||
API_USERNAME={username-here}
|
||||
API_PASSWORD={password-here}
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
To run the tests, use the following Maven command:
|
||||
```sh
|
||||
mvn test
|
||||
```
|
||||
|
||||
## Reporting
|
||||
Test output reports are generated in the `app-info.html` directory by default.
|
||||
|
||||
## Contributing
|
||||
Contributions are welcome! Please follow these steps to contribute:
|
||||
1. Fork the repository.
|
||||
2. Create a new branch (`git checkout -b feature-branch`).
|
||||
3. Make your changes.
|
||||
4. Commit your changes (`git commit -m 'Add some feature'`).
|
||||
5. Push to the branch (`git push origin feature-branch`).
|
||||
6. Open a pull request.
|
||||
|
||||
## License
|
||||
This project is licensed under the MIT License. See the [LICENSE](LICENSE.md) file for details.
|
||||
|
||||
---
|
||||
|
||||
Thank you for using the Automation API Testing Framework! If you have any questions, feel free to open an issue or contact the project maintainers.
|
||||
7
src/main/kotlin/org/example/api/ApiUtils.kt
Normal file
7
src/main/kotlin/org/example/api/ApiUtils.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
package org.example.api
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun createBasicAuthTokenForHeader(username: String, password: String) =
|
||||
StringBuilder("Basic ").append(Base64.getEncoder().encodeToString("$username:$password".toByteArray()))
|
||||
.toString()
|
||||
@@ -36,7 +36,6 @@ class BookerApi {
|
||||
.setLenient()
|
||||
.create()
|
||||
|
||||
|
||||
private fun buildOkHttpClient(timeoutSeconds: Long = 30L): OkHttpClient {
|
||||
val builder = OkHttpClient.Builder()
|
||||
|
||||
|
||||
@@ -33,20 +33,20 @@ interface RestfulBookerApi {
|
||||
suspend fun updateBooking(
|
||||
@Path("id") id: String,
|
||||
@Body booking: BookingRequest,
|
||||
@Header("Authorization") token: String
|
||||
@Header("Authorization") basicHeaderToken: String
|
||||
): Response<BookingResponse>
|
||||
|
||||
@Headers("Content-Type:application/json", "Accept: application/json")
|
||||
@PATCH("booking/{id}")
|
||||
suspend fun partialUpdateBooking(
|
||||
@Path("id") id: String,
|
||||
@Header("Authorization") token: String,
|
||||
@Header("Authorization") basicHeaderToken: String,
|
||||
@Body update: UpdateBookingRequest
|
||||
): Response<BookingResponse>
|
||||
|
||||
@DELETE("booking/{id}")
|
||||
suspend fun deleteBooking(
|
||||
@Path("id") id: String,
|
||||
@Header("Authorization") token: String
|
||||
@Header("Authorization") basicHeaderToken: String
|
||||
): Response<Any>
|
||||
}
|
||||
@@ -7,5 +7,5 @@ data class BookingResponse(
|
||||
var totalprice: Int,
|
||||
var depositpaid: Boolean,
|
||||
var bookingdates: Bookingdates,
|
||||
var additionalneeds: String
|
||||
var additionalneeds: String?
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="warn">
|
||||
<Properties>
|
||||
<Property name="basePath">Classpath</Property>
|
||||
<Property name="basePath">./</Property>
|
||||
</Properties>
|
||||
<Appenders>
|
||||
<RollingFile name="fileLogger" fileName="${basePath}/app-info.html"
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package org.example
|
||||
|
||||
import io.github.cdimascio.dotenv.dotenv
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.message.MessageFormatMessage
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
|
||||
abstract class NetworkTests {
|
||||
abstract class BaseNetworkTests {
|
||||
private val logger = LogManager.getLogger(Tests::javaClass)
|
||||
|
||||
private val env by lazy { dotenv() }
|
||||
|
||||
// Call retrofit API and unwrap response or throw exception
|
||||
fun <T : Any> responseUnwrap(
|
||||
@@ -22,4 +28,8 @@ abstract class NetworkTests {
|
||||
}
|
||||
}
|
||||
|
||||
fun getStoredVariable(key: String) = env.get(key)
|
||||
|
||||
fun logMessage(logMessage: String) = logger.info(logMessage)
|
||||
fun logMessage(logMessage: MessageFormatMessage) = logger.info(logMessage)
|
||||
}
|
||||
@@ -2,26 +2,25 @@ package org.example
|
||||
|
||||
import org.example.api.BookerApi
|
||||
import org.example.api.RestfulBookerApi
|
||||
import org.example.model.AuthRequest
|
||||
import org.example.model.BookingRequest
|
||||
import org.example.model.Bookingdates
|
||||
import org.example.model.UpdateBookingRequest
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.message.MessageFormatMessage
|
||||
import org.assertj.core.api.AssertionsForClassTypes.assertThat
|
||||
import org.example.api.createBasicAuthTokenForHeader
|
||||
import org.junit.jupiter.api.*
|
||||
import org.example.storage.OrdersDatabase
|
||||
import org.example.utils.FileReader
|
||||
import org.example.utils.TestHelper
|
||||
import org.example.utils.PASSWORD_KEY
|
||||
import org.example.utils.USERNAME_KEY
|
||||
import java.util.*
|
||||
|
||||
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
|
||||
class Tests : NetworkTests() {
|
||||
class Tests : BaseNetworkTests() {
|
||||
|
||||
companion object {
|
||||
private lateinit var bookerApi: RestfulBookerApi
|
||||
private val fileReader = FileReader()
|
||||
private val logger = LogManager.getLogger(Tests::javaClass)
|
||||
private val testHelper = TestHelper()
|
||||
|
||||
private val storage = OrdersDatabase()
|
||||
|
||||
@@ -33,8 +32,8 @@ class Tests : NetworkTests() {
|
||||
internal fun beforeAll() {
|
||||
bookerApi = BookerApi().invoke()
|
||||
|
||||
bookingRequestTestOne = fileReader.readJsonFileFromResources("test1", BookingRequest::class.java)
|
||||
bookingRequestTestTwo = fileReader.readJsonFileFromResources("test2", BookingRequest::class.java)
|
||||
bookingRequestTestOne = testHelper.readJsonFileFromResources("test1", BookingRequest::class.java)
|
||||
bookingRequestTestTwo = testHelper.readJsonFileFromResources("test2", BookingRequest::class.java)
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@@ -56,17 +55,7 @@ class Tests : NetworkTests() {
|
||||
/*
|
||||
* Given
|
||||
*/
|
||||
val bookingRequestThree = BookingRequest(
|
||||
firstname = "Mark",
|
||||
lastname = "Wahlberg",
|
||||
totalprice = 750,
|
||||
depositpaid = true,
|
||||
bookingdates = Bookingdates(
|
||||
checkin = "2025-01-01",
|
||||
checkout = "2025-01-10"
|
||||
),
|
||||
additionalneeds = "Breakfast"
|
||||
)
|
||||
val bookingRequestThree = testHelper.readJsonFileFromResources("test3", BookingRequest::class.java)
|
||||
|
||||
/*
|
||||
* When
|
||||
@@ -85,17 +74,17 @@ class Tests : NetworkTests() {
|
||||
.isGreaterThanOrEqualTo(3)
|
||||
val bookingIds = bookingIdsResponse.map { it.bookingid }.joinToString()
|
||||
|
||||
logger.info("Available booking IDs: $bookingIds")
|
||||
logMessage("Available booking IDs: $bookingIds")
|
||||
|
||||
// Add the booking details and idea for later
|
||||
bookingResponses.forEach { response ->
|
||||
storage.insertBooking(response.bookingid, response.booking)
|
||||
|
||||
logger.trace(
|
||||
logMessage(
|
||||
MessageFormatMessage(
|
||||
"Booking with ID: {0} has been added: {1}",
|
||||
response.bookingid,
|
||||
response.booking
|
||||
testHelper.toJsonString(response.booking)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -130,21 +119,11 @@ class Tests : NetworkTests() {
|
||||
/*
|
||||
* When
|
||||
*/
|
||||
val auth = responseUnwrap {
|
||||
bookerApi.createAuthToken(
|
||||
AuthRequest(
|
||||
UUID.randomUUID().toString(),
|
||||
UUID.randomUUID().toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
val tokenBuilder =
|
||||
StringBuilder("Basic ").append(Base64.getEncoder().encodeToString("admin:password123".toByteArray()))
|
||||
.toString()
|
||||
val tokenBuilder = buildBasicAuthToken()
|
||||
val updateTestOneResponse = responseUnwrap {
|
||||
bookerApi.partialUpdateBooking(
|
||||
id = orderIdTestOne.toString(),
|
||||
token = tokenBuilder,
|
||||
basicHeaderToken = tokenBuilder,
|
||||
update = UpdateBookingRequest(
|
||||
totalprice = 1000
|
||||
)
|
||||
@@ -155,7 +134,7 @@ class Tests : NetworkTests() {
|
||||
val updateTestTwoResponse = responseUnwrap {
|
||||
bookerApi.partialUpdateBooking(
|
||||
id = orderIdTestTwo.toString(),
|
||||
token = tokenBuilder,
|
||||
basicHeaderToken = tokenBuilder,
|
||||
update = UpdateBookingRequest(
|
||||
totalprice = 1500
|
||||
)
|
||||
@@ -163,23 +142,22 @@ class Tests : NetworkTests() {
|
||||
}.also {
|
||||
storage.updateCompleteOrder(orderIdTestTwo, it)
|
||||
}
|
||||
val updateResponseList = listOf(updateTestOneResponse, updateTestTwoResponse)
|
||||
|
||||
/*
|
||||
* Then
|
||||
*/
|
||||
logger.info(
|
||||
logMessage(
|
||||
MessageFormatMessage(
|
||||
"Booking with ID: {0} has been updated to the following: {1}",
|
||||
orderIdTestOne,
|
||||
updateTestOneResponse
|
||||
testHelper.toJsonString(updateTestOneResponse)
|
||||
)
|
||||
)
|
||||
logger.info(
|
||||
logMessage(
|
||||
MessageFormatMessage(
|
||||
"Booking with ID: {0} has been updated to the following: {1}",
|
||||
orderIdTestTwo,
|
||||
updateTestTwoResponse
|
||||
testHelper.toJsonString(updateTestTwoResponse)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -205,11 +183,11 @@ class Tests : NetworkTests() {
|
||||
/*
|
||||
* Then
|
||||
*/
|
||||
logger.info(
|
||||
logMessage(
|
||||
MessageFormatMessage(
|
||||
"Booking with ID: {0} has been delete and given the following response: {1}",
|
||||
idOfAny,
|
||||
deleteResponse
|
||||
testHelper.toJsonString(deleteResponse)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -220,6 +198,7 @@ class Tests : NetworkTests() {
|
||||
/*
|
||||
* Given
|
||||
*/
|
||||
println("The log4j library will create the report in the root of the folder")
|
||||
|
||||
/*
|
||||
* When
|
||||
@@ -229,4 +208,14 @@ class Tests : NetworkTests() {
|
||||
* Then
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* build a basic header token needed for using end points like partial update
|
||||
*/
|
||||
private fun buildBasicAuthToken(): String {
|
||||
val username = getStoredVariable(USERNAME_KEY)
|
||||
val password = getStoredVariable(PASSWORD_KEY)
|
||||
|
||||
return createBasicAuthTokenForHeader(username, password)
|
||||
}
|
||||
}
|
||||
4
src/test/kotlin/org/example/utils/Constants.kt
Normal file
4
src/test/kotlin/org/example/utils/Constants.kt
Normal file
@@ -0,0 +1,4 @@
|
||||
package org.example.utils
|
||||
|
||||
const val USERNAME_KEY = "API_USERNAME"
|
||||
const val PASSWORD_KEY = "API_PASSWORD"
|
||||
@@ -2,10 +2,8 @@ package org.example.utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import java.io.BufferedReader
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class FileReader {
|
||||
class TestHelper {
|
||||
|
||||
private val gson by lazy { Gson() }
|
||||
|
||||
@@ -18,4 +16,6 @@ class FileReader {
|
||||
val data = iStream.bufferedReader().use(BufferedReader::readText)
|
||||
return gson.fromJson(data, clazz)
|
||||
}
|
||||
|
||||
fun toJsonString(any: Any) = gson.toJson(any)
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"firstname" : "Jim",
|
||||
"lastname" : "Brown",
|
||||
"totalprice" : 500,
|
||||
"depositpaid" : true,
|
||||
"firstname" : "Andrea",
|
||||
"lastname" : "Sims",
|
||||
"totalprice" : 1000,
|
||||
"depositpaid" : false,
|
||||
"bookingdates" : {
|
||||
"checkin" : "2025-01-01",
|
||||
"checkout" : "2025-01-10"
|
||||
},
|
||||
"additionalneeds" : "Lunch"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"firstname" : "Jim",
|
||||
"lastname" : "Brown",
|
||||
"totalprice" : 500,
|
||||
"firstname" : "Mark",
|
||||
"lastname" : "Wahlberg",
|
||||
"totalprice" : 1500,
|
||||
"depositpaid" : true,
|
||||
"bookingdates" : {
|
||||
"checkin" : "2025-01-01",
|
||||
"checkout" : "2025-01-10"
|
||||
},
|
||||
"additionalneeds" : "Lunch"
|
||||
"additionalneeds" : "Lunch|Dinner"
|
||||
}
|
||||
Reference in New Issue
Block a user