DEV Community

Farida
Farida

Posted on

Kotlin test automation. Chapter 1- Framework and CRUD tests.

What we're going to test and how we're going to do it?
I've chosen an open API https://fakestoreapi.com/
It has GET, POST, PUT, PATCH and DELETE methods so we'll be able to try writing tests not only for GET methods.
I'd like to write smoke tests first as a best practice. It'll be some positive cases like getting an info about exact product, list of all the products, addition of a new product and deleting it.
When working with APIs, creating CRUD (Create, Read, Update, Delete) tests is essential to validate the functionality of your endpoints.
Let's start from smth small!

🚲Step by step

We will use the RestAssured library for HTTP interactions and JUnit for test assertions.

Project Setup

  1. Add these dependencies to your build.gradle:
   dependencies {
       testImplementation "io.rest-assured:rest-assured:4.3.3"
       testImplementation "org.junit.jupiter:junit-jupiter:5.7.0"
       testImplementation "com.google.code.gson:gson:2.8.6"
   }
Enter fullscreen mode Exit fullscreen mode
  1. Import necessary packages in your test file:
   import io.restassured.RestAssured.*
   import io.restassured.http.ContentType
   import io.restassured.response.Response
   import org.junit.jupiter.api.Assertions.*
   import org.junit.jupiter.api.Test
   import com.google.gson.Gson
Enter fullscreen mode Exit fullscreen mode

We'll test the /products resource in FakeStoreAPI.

1. GET Request (Positive and Negative)

A GET request fetches data from the API. We’ll test fetching a single product and handling an invalid ID.

Positive Scenario
@Test
fun `test get product by ID - positive`() {
    val response: Response = given()
        .contentType(ContentType.JSON)
        .get("https://fakestoreapi.com/products/1")
        .then()
        .statusCode(200)
        .extract().response()

    val jsonResponse = response.asString()
    assertNotNull(jsonResponse)
    assertTrue(jsonResponse.contains("id"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode
Negative Scenario (Invalid Product ID)
@Test
fun `test get product by invalid ID - negative`() {
    val response: Response = given()
        .contentType(ContentType.JSON)
        .get("https://fakestoreapi.com/products/999999")
        .then()
        .statusCode(404)  // Expecting Not Found
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("error"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode

2. POST Request (Create Product)

In a POST request, we send data to create a new resource. We'll create a new product and handle the response.

Positive Scenario
data class Product(val title: String, val price: Double, val description: String, val category: String, val image: String)

@Test
fun `test create product - positive`() {
    val product = Product("New Product", 29.99, "A test product", "electronics", "https://i.imgur.com/EHyR2nP.png")

    val response: Response = given()
        .contentType(ContentType.JSON)
        .body(Gson().toJson(product))
        .post("https://fakestoreapi.com/products")
        .then()
        .statusCode(201)
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("New Product"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode
Negative Scenario (Missing Fields)
@Test
fun `test create product with missing fields - negative`() {
    val incompleteProduct = mapOf("title" to "Incomplete Product")

    val response: Response = given()
        .contentType(ContentType.JSON)
        .body(Gson().toJson(incompleteProduct))
        .post("https://fakestoreapi.com/products")
        .then()
        .statusCode(400)  // Bad Request due to missing required fields
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("error"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode

3. PUT Request (Update Product)

A PUT request is used to update an existing resource. We’ll update the product’s price.

Positive Scenario
@Test
fun `test update product - positive`() {
    val updatedProduct = Product("Updated Product", 49.99, "Updated description", "electronics", "https://i.imgur.com/EHyR2nP.png")

    val response: Response = given()
        .contentType(ContentType.JSON)
        .body(Gson().toJson(updatedProduct))
        .put("https://fakestoreapi.com/products/1")
        .then()
        .statusCode(200)
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("Updated Product"))
    assertTrue(jsonResponse.contains("49.99"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode
Negative Scenario (Invalid Product ID)
@Test
fun `test update product with invalid ID - negative`() {
    val updatedProduct = Product("Non-existent Product", 19.99, "This should fail", "electronics", "https://i.imgur.com/EHyR2nP.png")

    val response: Response = given()
        .contentType(ContentType.JSON)
        .body(Gson().toJson(updatedProduct))
        .put("https://fakestoreapi.com/products/999999")
        .then()
        .statusCode(404)
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("error"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode

4. PATCH Request (Partial Update)

A PATCH request is used to partially update a resource. Let’s update just the price of an existing product.

Positive Scenario
@Test
fun `test patch product price - positive`() {
    val updateData = mapOf("price" to 59.99)

    val response: Response = given()
        .contentType(ContentType.JSON)
        .body(Gson().toJson(updateData))
        .patch("https://fakestoreapi.com/products/1")
        .then()
        .statusCode(200)
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("59.99"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode
Negative Scenario (Invalid Field)
@Test
fun `test patch product with invalid field - negative`() {
    val invalidUpdateData = mapOf("nonExistentField" to "new value")

    val response: Response = given()
        .contentType(ContentType.JSON)
        .body(Gson().toJson(invalidUpdateData))
        .patch("https://fakestoreapi.com/products/1")
        .then()
        .statusCode(400)
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("error"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode

5. DELETE Request (Delete a Product)

The DELETE request removes a resource from the server.

Positive Scenario
@Test
fun `test delete product - positive`() {
    val response: Response = given()
        .contentType(ContentType.JSON)
        .delete("https://fakestoreapi.com/products/1")
        .then()
        .statusCode(200)
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("1"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode
Negative Scenario (Deleting Non-existent Product)
@Test
fun `test delete non-existent product - negative`() {
    val response: Response = given()
        .contentType(ContentType.JSON)
        .delete("https://fakestoreapi.com/products/999999")
        .then()
        .statusCode(404)
        .extract().response()

    val jsonResponse = response.asString()
    assertTrue(jsonResponse.contains("error"))
    println("Response: $jsonResponse")
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

By using Kotlin, RestAssured, and JUnit, you can automate the process of testing API endpoints for various HTTP requests like GET, POST, PUT, PATCH, and DELETE. Testing both positive and negative scenarios helps ensure your API handles real-world cases and edge cases effectively.

Now, you can use these examples to build your own test cases and start automating the validation of your RESTful APIs!

Top comments (0)