mirror of
https://github.com/hmalik144/api-testing-automation-framework.git
synced 2026-03-18 07:26:17 +00:00
Initial commit
- Retrofit used to call API
This commit is contained in:
37
src/main/kotlin/api/BookerApi.kt
Normal file
37
src/main/kotlin/api/BookerApi.kt
Normal file
@@ -0,0 +1,37 @@
|
||||
package api
|
||||
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
||||
class BookerApi {
|
||||
private val baseUrl = "https://restful-booker.herokuapp.com/"
|
||||
|
||||
private val loggingInterceptor = HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
}
|
||||
|
||||
private fun buildOkHttpClient(timeoutSeconds: Long = 30L): OkHttpClient {
|
||||
val builder = OkHttpClient.Builder()
|
||||
|
||||
builder
|
||||
.addInterceptor(loggingInterceptor)
|
||||
.connectTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
||||
.writeTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
||||
.readTimeout(timeoutSeconds, TimeUnit.SECONDS)
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
fun invoke(): RestfulBookerApi {
|
||||
val okHttpClient = buildOkHttpClient()
|
||||
return Retrofit.Builder()
|
||||
.client(okHttpClient)
|
||||
.baseUrl(baseUrl)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(RestfulBookerApi::class.java)
|
||||
}
|
||||
}
|
||||
61
src/main/kotlin/api/RestfulBookerApi.kt
Normal file
61
src/main/kotlin/api/RestfulBookerApi.kt
Normal file
@@ -0,0 +1,61 @@
|
||||
package api
|
||||
|
||||
import model.*
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.*
|
||||
|
||||
interface RestfulBookerApi {
|
||||
|
||||
@Headers("Content-Type:application/json")
|
||||
@POST("auth")
|
||||
suspend fun createAuthToken(
|
||||
@Field("username") username: String,
|
||||
@Field("password") password: String,
|
||||
): Response<AuthResponse>
|
||||
|
||||
@GET("booking")
|
||||
suspend fun getBookingIds(
|
||||
@Field("firstname") firstname: String? = null,
|
||||
@Field("lastname") lastname: String? = null,
|
||||
@Field("checkin") checkin: String? = null,
|
||||
@Field("checkout") checkout: String? = null,
|
||||
): Response<List<BookingIdResponse>>
|
||||
|
||||
@GET("booking/{id}")
|
||||
suspend fun getSingleBooking(
|
||||
@Path("id") id: String
|
||||
): Response<BookingResponse>
|
||||
|
||||
@Headers("Content-Type:application/json")
|
||||
@POST("booking")
|
||||
suspend fun createBooking(
|
||||
@Body booking: BookingRequest,
|
||||
): Response<CreateBookingResponse>
|
||||
|
||||
@Headers("Content-Type:application/json", "Accept: application/json")
|
||||
@PUT("booking/{id}")
|
||||
suspend fun updateBooking(
|
||||
@Path("id") id: String,
|
||||
@Body booking: BookingRequest,
|
||||
@Header("Authorization") token: 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,
|
||||
@Field("firstname") firstname: String? = null,
|
||||
@Field("lastname") lastname: String? = null,
|
||||
@Field("totalprice") totalprice: Float? = null,
|
||||
@Field("depositpaid") depositpaid: Boolean? = null,
|
||||
@Field("checkin") checkin: String? = null,
|
||||
@Field("checkout") checkout: String? = null,
|
||||
@Field("additionalneeds") additionalneeds: String? = null
|
||||
): Response<BookingResponse>
|
||||
|
||||
@DELETE("booking/{id}")
|
||||
suspend fun deleteBooking(
|
||||
@Path("id") id: String
|
||||
): Response<Any>
|
||||
}
|
||||
5
src/main/kotlin/model/AuthResponse.kt
Normal file
5
src/main/kotlin/model/AuthResponse.kt
Normal file
@@ -0,0 +1,5 @@
|
||||
package model
|
||||
|
||||
class AuthResponse {
|
||||
var token: String? = null
|
||||
}
|
||||
5
src/main/kotlin/model/BookingIdResponse.kt
Normal file
5
src/main/kotlin/model/BookingIdResponse.kt
Normal file
@@ -0,0 +1,5 @@
|
||||
package model
|
||||
|
||||
class BookingIdResponse {
|
||||
var bookingid = 0
|
||||
}
|
||||
12
src/main/kotlin/model/BookingRequest.kt
Normal file
12
src/main/kotlin/model/BookingRequest.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package model
|
||||
|
||||
data class BookingRequest (
|
||||
var firstname: String? = null,
|
||||
var lastname: String? = null,
|
||||
var totalprice: Int = 0,
|
||||
var depositpaid: Boolean = false,
|
||||
var bookingdates: Bookingdates? = null,
|
||||
var additionalneeds: String? = null,
|
||||
)
|
||||
|
||||
|
||||
11
src/main/kotlin/model/BookingResponse.kt
Normal file
11
src/main/kotlin/model/BookingResponse.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
|
||||
data class BookingResponse (
|
||||
var firstname: String? = null,
|
||||
var lastname: String? = null,
|
||||
var totalprice: Int = 0,
|
||||
var depositpaid: Boolean = false,
|
||||
var bookingdates: Bookingdates? = null,
|
||||
var additionalneeds: String? = null
|
||||
)
|
||||
6
src/main/kotlin/model/Bookingdates.kt
Normal file
6
src/main/kotlin/model/Bookingdates.kt
Normal file
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
data class Bookingdates (
|
||||
var checkin: String? = null,
|
||||
var checkout: String? = null,
|
||||
)
|
||||
6
src/main/kotlin/model/CreateBookingResponse.kt
Normal file
6
src/main/kotlin/model/CreateBookingResponse.kt
Normal file
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
class CreateBookingResponse {
|
||||
var bookingid = 0
|
||||
var booking: BookingResponse? = null
|
||||
}
|
||||
20
src/test/kotlin/NetworkTests.kt
Normal file
20
src/test/kotlin/NetworkTests.kt
Normal file
@@ -0,0 +1,20 @@
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
|
||||
abstract class NetworkTests {
|
||||
|
||||
fun <T : Any> responseUnwrap(
|
||||
call: suspend () -> Response<T>
|
||||
): T {
|
||||
|
||||
val response = runBlocking { call.invoke() }
|
||||
if (response.isSuccessful) {
|
||||
return response.body()!!
|
||||
} else {
|
||||
val error = response.errorBody()?.string()
|
||||
|
||||
throw IOException(error ?: "Unable to handle end point")
|
||||
}
|
||||
}
|
||||
}
|
||||
105
src/test/kotlin/Tests.kt
Normal file
105
src/test/kotlin/Tests.kt
Normal file
@@ -0,0 +1,105 @@
|
||||
import api.BookerApi
|
||||
import api.RestfulBookerApi
|
||||
import io.restassured.RestAssured.given
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import model.BookingRequest
|
||||
import model.Bookingdates
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.junit.FixMethodOrder
|
||||
import org.junit.jupiter.api.AfterAll
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.runners.MethodSorters
|
||||
import utils.FileReader
|
||||
|
||||
@FixMethodOrder(MethodSorters.DEFAULT)
|
||||
class Tests : NetworkTests(){
|
||||
|
||||
companion object {
|
||||
private lateinit var bookerApi: RestfulBookerApi
|
||||
private lateinit var fileReader: FileReader
|
||||
private val logger = LogManager.getLogger(Tests::class.java)
|
||||
|
||||
@BeforeAll
|
||||
@JvmStatic
|
||||
internal fun beforeAll() {
|
||||
bookerApi = BookerApi().invoke()
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@JvmStatic
|
||||
internal fun afterAll() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 1. Generate 3 new bookings --> Log below scenarios to a log file
|
||||
* o All available booking ID's
|
||||
* o Above added 3 new booking details
|
||||
*/
|
||||
@Test()
|
||||
fun testScenarioOne() {
|
||||
// Given
|
||||
val bookingRequestOne = fileReader.readJsonFileFromResources<BookingRequest>("test1")
|
||||
val bookingRequestTwo = fileReader.readJsonFileFromResources<BookingRequest>("test2")
|
||||
val bookingRequestThree = BookingRequest(
|
||||
firstname = "Mark",
|
||||
lastname = "Wahlberg",
|
||||
totalprice = 750,
|
||||
depositpaid = true,
|
||||
bookingdates = Bookingdates(
|
||||
checkin = "2025-01-01",
|
||||
checkout = "2025-01-10"
|
||||
),
|
||||
additionalneeds = "Breakfast"
|
||||
)
|
||||
|
||||
// When
|
||||
val createBookingOneResponse = responseUnwrap { bookerApi.createBooking(bookingRequestOne) }
|
||||
val createBookingTwoResponse = responseUnwrap { bookerApi.createBooking(bookingRequestTwo) }
|
||||
val createBookingThreeResponse = responseUnwrap { bookerApi.createBooking(bookingRequestThree) }
|
||||
|
||||
// Then
|
||||
val bookingIds = responseUnwrap { bookerApi.getBookingIds() }
|
||||
logger.trace("Available booking IDs: ${bookingIds.joinToString()}")
|
||||
bookingIds.forEach {
|
||||
val currentBookingResponse = responseUnwrap { bookerApi.getSingleBooking("$it") }
|
||||
logger.trace(currentBookingResponse)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2. Modify total price for test1 to 1000 and test2 to 1500. Log this data to same log file.
|
||||
* Test data :
|
||||
* • Test1 with total price 500 who deposit is paid with random check in and checkout dates and having preference of lunch as additional need.
|
||||
*
|
||||
*/
|
||||
@Test()
|
||||
fun testScenarioTwo() {
|
||||
// Given
|
||||
|
||||
// When
|
||||
|
||||
// Then
|
||||
}
|
||||
|
||||
@Test()
|
||||
fun testScenarioThree() {
|
||||
// Given
|
||||
|
||||
// When
|
||||
|
||||
// Then
|
||||
}
|
||||
|
||||
@Test()
|
||||
fun testScenarioFour() {
|
||||
// Given
|
||||
|
||||
// When
|
||||
|
||||
// Then
|
||||
}
|
||||
}
|
||||
21
src/test/kotlin/utils/FileReader.kt
Normal file
21
src/test/kotlin/utils/FileReader.kt
Normal file
@@ -0,0 +1,21 @@
|
||||
package utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import java.io.BufferedReader
|
||||
import java.lang.reflect.ParameterizedType
|
||||
|
||||
class FileReader {
|
||||
|
||||
private val gson by lazy { Gson() }
|
||||
|
||||
fun <T : Any?> readJsonFileFromResources(fileName: String): T {
|
||||
val iStream = this::class.java.getResourceAsStream("$fileName.json")
|
||||
?: throw IllegalStateException("Unable to read the file requested")
|
||||
val data = iStream.bufferedReader().use(BufferedReader::readText)
|
||||
val genericType = ((javaClass.genericSuperclass as? ParameterizedType)
|
||||
?.actualTypeArguments?.getOrNull(0) as? Class<T>)
|
||||
?: throw IllegalStateException("Can not find class from generic argument")
|
||||
|
||||
return gson.fromJson(data, genericType)
|
||||
}
|
||||
}
|
||||
11
src/test/resources/test1.json
Normal file
11
src/test/resources/test1.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"firstname" : "Jim",
|
||||
"lastname" : "Brown",
|
||||
"totalprice" : 500,
|
||||
"depositpaid" : true,
|
||||
"bookingdates" : {
|
||||
"checkin" : "2025-01-01",
|
||||
"checkout" : "2025-01-10"
|
||||
},
|
||||
"additionalneeds" : "Lunch"
|
||||
}
|
||||
11
src/test/resources/test2.json
Normal file
11
src/test/resources/test2.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"firstname" : "Jim",
|
||||
"lastname" : "Brown",
|
||||
"totalprice" : 500,
|
||||
"depositpaid" : true,
|
||||
"bookingdates" : {
|
||||
"checkin" : "2025-01-01",
|
||||
"checkout" : "2025-01-10"
|
||||
},
|
||||
"additionalneeds" : "Lunch"
|
||||
}
|
||||
Reference in New Issue
Block a user