Karate vs. REST-Assured: Pruebas automatizadas de API con Java

Las pruebas de API son una etapa crítica del proceso de control de calidad que consiste en analizar las interfaces de programas de aplicación (API) para evaluar su funcionalidad, seguridad, rendimiento y fiabilidad.

En particular, en el caso de aplicaciones complejas, la API puede constar de docenas de puntos finales y activadores que se afectan mutuamente. Para evitar que surjan problemas de regresión en producción, es muy beneficioso disponer de un conjunto de pruebas automatizadas de extremo a extremo. Sin embargo, antes de poner en marcha estas pruebas, los ingenieros de control de calidad de automatización (AQA) y la dirección deben determinar el marco en el que se basarán estas pruebas.

En este artículo, exploraremos y compararemos los dos marcos de pruebas de API más populares del mercado: Karate y REST-Assured. Ambos marcos están basados en Java. La comparación que se ofrece le ayudará a decidir qué marco se adapta mejor a sus necesidades específicas. Empecemos.

Visión general del kárate

Karate es un framework de código abierto relativamente nuevo que permite a los evaluadores, incluso sin conocimientos de programación, realizar pruebas de API, servicios web y microservicios. Podrías suponer que se originó en Japón, ¿verdad? En realidad, este marco fue desarrollado por Peter Thomas en 2017 y desde entonces ha sido adoptado por empresas de todo el mundo.

Profundicemos en los detalles de la herramienta Karate. En cuanto a la instalación, Karate está disponible como un único archivo JARJAR ejecutable. También puede añadirse como dependencia de Maven al archivo pom.xml. Si prefiere no integrarlo con un marco de pruebas, puede optar por la versión básica:

<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-core -->
<dependency>
<groupId>com.intuit.karate</groupId>
  <artifactId>karate-core</artifactId>
     <version>1.2.0</version>
</dependency>

Por lo demás, existen versiones compatibles con los marcos de pruebas TestNG y JUnit.

<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-junit5 -->
<dependency>
     <groupId>com.intuit.karate</groupId>
     <artifactId>karate-junit5</artifactId>
     <version>1.2.0 </version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.intuit.karate/karate-testng -->
<dependency>
     <groupId>com.intuit.karate</groupId>
     <artifactId>karate-testng</artifactId>
     <version>0.8.0.1</version>
</dependency>

Karate utiliza su propio lenguaje de scripting de pruebas llamado “Karate-Script”. Si tiene experiencia con marcos de desarrollo basado en el comportamiento (BDD) como Cucumber, verá que la estructura del código de Karate se le parece mucho:

Feature: sample karate test script
 for help, see https://github.com/karatelabs/karate/wiki/IDE-support

 Background:
   * url 'https://jsonplaceholder.typicode.com/'

   Scenario: get all users and then get the first user by id
     Given path 'users'
     When method get
     Then status 200

     * def first = response[0]

     Given path 'users', first.id
     When method get
     Then status 200
     And assert response.name == "Leanne Graham"
     And assert response.email == "Sincere@april.biz"

De hecho, el kárate comparte muchas similitudes con el pepino:

  1. palabras clave como “Feature”, “Scenario”, “Given”, “When”, “Then”, “And”
  2. almacenamiento de pruebas en archivos .feature

Sin embargo, el principal factor diferenciador de Karate es que “todas las definiciones de los pasos ya están escritas para nosotros”. Esto resulta especialmente ventajoso para las pruebas de API. A diferencia de las pruebas de interfaz de usuario, las pruebas de API suelen seguir un esquema uniforme:

  1. Fondo
  2. Suministro de parámetros de solicitud
  3. Validación del estado de la respuesta

Así que tiene mucho sentido utilizar definiciones de pasos ya preparadas en lugar de crear las suyas propias. Veamos ahora cómo maneja Karate los tres pasos mencionados.

Fondo

El fondo suele incluir propiedades comunes que comparten todos los escenarios del archivo .feature. Algunas de estas propiedades ya están predefinidas, como la URL:

Fondo:
 * url 'https://jsonplaceholder.typicode.com'

Y puede definir directamente variables en el archivo de características utilizando la palabra clave “def”:

* def user =
 """
 {
   "name": "Test User",
   "username": "testuser",
   "email": "test@user.com",
   "address": {
     "street": "Has No Name",
     "suite": "Apt. 123",
     "city": "Electri",
     "zipcode": "54321-6789"
   }
 }
 """

Proporcionar los parámetros de la petición

En primer lugar, tenemos que proporcionar una ruta que también puede incluir parámetros de consulta separados por comas.

Dada la ruta 'users', 1234

A continuación, podemos incluir la carga útil de la solicitud si es necesario, que admite los formatos JSON y XML.

JSON:

Y solicitud 
{"name":"Vidhya","age":29,"locale":"en","twitter":"VidhyaJava","email":"it.vidhyadharan@gmail.com"}

XML:

 * def payload =
 """
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
"""
 Y solicitud  payload

Por último, especificamos el método HTTP para la solicitud, que puede ser uno de los siguientes: get, post, delete, patch o put.

Cuando el método  get

Validación de la respuesta

En primer lugar, validamos el código de respuesta para los casos de prueba positivos (200, 201) y negativos (4xx).

A continuación, estado 201
A continuación, estado 404

A continuación, procedemos a la validación del esquema de respuesta, donde podemos verificar la carga útil de la respuesta tanto en formato JSON como XML. En el caso de JSON:

{
  "id": 1,
  "name": "Leanne Graham",
  "nombre de usuario": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "calle": "Kulas Light",
    "suite": "Apt. 556",
    "ciudad": "Gwenborough",
    "código postal": "92998-3874",
    "geo": {
      "lat": "-37.3159",
      "lng": "81.1496"
    }
  },
  "phone": "1-770-736-8031 x56442",
  "website": "hildegard.org",
  "empresa": {
    "nombre": "Romaguera-Crona",
    "catchPhrase": "Red neuronal cliente-servidor multicapa",
    "bs": "aprovechar los mercados electrónicos en tiempo real"
  }
}

Si queremos validar propiedades específicas, las aserciones pueden incluir:

Y assert response.name == "Leanne Graham"
Y assert response.email == "Sincere@april.biz"

Sin embargo, es importante señalar que Karate proporciona un mecanismo integrado para validar toda la respuesta JSON, a diferencia de REST-Assured:

Y coincide response ==   {"id":1,"name":"LeanneGraham","username":"Bret",
"email":"Sincere@april.biz",
"address":{"street":"Kulas Light","suite":"Apt. 556",
"city":"Gwenborough","zipcode":"92998-3874",
"geo":{"lat":"-37.3159","lng":"81.1496"}},
"phone":"1-770-736-8031x56442",
"website":"hildegard.org",
"company":{"name":"Romaguera-Crona",
"catchPhrase":"Multi-layered client-server neural-net",
"bs":"harness real-time e-markets"}}

Karate incluye una herramienta de informes integrada que genera informes en el directorio target\karate-reports. El archivo de informe principal es karate-summary.html:

Karate vs. REST-Assured: Pruebas automatizadas de API con Java

REST-Assured general

REST-Assured es una libreria basada en Java creada por JayWay Company para agilizar las pruebas y validacion de Restful Web Services. Sirve como un catalizador eficiente para automatizar el proceso de prueba de APIs REST.

REST-Assured puede ser instalado facilmente agregando la dependencia de Maven:

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.1.1</version>
<scope>test</scope>
</dependency>

Se requiere un framework de pruebas como JUnit o TestNG como ejecutor de pruebas. El siguiente ejemplo de código demuestra el uso de JUnit. Ahora, echemos un vistazo a un caso de prueba basado en REST-Assured:

public class UsersTest {

   @Before
   public void setup() {
       RestAssured.baseURI = "https://jsonplaceholder.typicode.com/";
   }

   @Test
   public void getAllUsersAndThenGetFirstUserById() {
       Response responseAllUsers =
               given()
                       .when()
                       .get("/users")
                       .then()
                       .statusCode(200)
                       .extract()
                       .response();

       int firstUserId = responseAllUsers.jsonPath().getInt("id[0]");

       Response responseFirstUser =
               given()
                       .pathParam("id", firstUserId)
                       .when()
                       .get("/users/{id}")
                       .then()
                       .statusCode(200)
                       .extract()
                       .response();
       Assert.assertEquals(responseFirstUser.jsonPath().getString("name"), 
      "Leanne Graham");
       Assert.assertEquals(responseFirstUser.jsonPath().getString("email"), 
       "Sincere@april.biz");
   }
}

Podemos ver que las pruebas basadas en REST-Assured están escritas en un formato estilo BDD, siguiendo la estructura Dado-Entonces-Entonces. Sin embargo, a diferencia de Karate, estas pruebas están incrustadas dentro del código Java. En otras palabras, para ver los casos de prueba implementados, hay que profundizar en las pruebas de la API y examinar el código. Por defecto, REST-Assured no utiliza archivos .feature, aunque puede integrarse con herramientas como Cucumber u otros marcos BDD.

REST-Assured maneja las etapas del esquema de pruebas de API de la siguiente manera (utilizando el ejemplo del marco de pruebas JUnit):

Fondo

Podemos utilizar simplemente la anotación @Before:

@Before
public void setup() {
   RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
}

Proporcionar los parámetros de la petición

Esta etapa está dividida en 2 partes por las palabras clave given() y when().

  1. Con given(), podemos proporcionar el tipo de contenido y el cuerpo de la petición, si es necesario. Es posible pasar cargas JSON o XML a un objeto String:
public void createUser() {
   String body = "{\"name\": \"Test User\"," +
           "\"username\": \"testuser\", " +
           "\"email\": \"test@user.com\"," +
           "\"address\": " +
           "{ \"street\": \"Has No Name\"," +
           "\"suite\": \"Apt. 123\"," +
           "\"city\": \"Electri\"," +
           "\"zipcode\": \"54321-6789\"}}";
   Response response =
           given()
                   .contentType(ContentType.JSON)
                   .body(body)

Un enfoque más preciso es utilizar el mapeo de objetos cuando se trabaja con REST-Assured. Defina el esquema de carga útil de la solicitud en la clase adecuada:

public static class User {
   private String name;
   private String username;

   public User(String name, String username) {
       this.name = name;
       this.username = username;
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public String getUsername() {
       return username;
   }

   public void setUsername(String job) {
       this.username = username;
   }
}

A continuación, puede simplemente pasar una nueva instancia de la clase en la carga útil de la solicitud:

@Test
public void createUser() {
   User user = new User("Test User", "testuser");
   Response response =
           given()
                   .contentType(ContentType.JSON)
                   .body(user)

Alternativamente, podemos importar la carga útil directamente desde un archivo:

@Test
public void createUserXML() {
   File xmlDataInFile = new File("src/test/resources/user.xml");
   Response response =
           given()
                   .contentType(ContentType.XML)
                   .body(xmlDataInFile)
  1. Con when() necesitamos especificar la ruta y el método:
.when()
.get("/users")

La ruta en REST-Assured también acepta variables:

int firstUserId = 123;
*********************
.pathParam("id", firstUserId)
.when()
.get("/users/{id}")

Validación de la respuesta

La validación de la respuesta se realiza mediante la palabra clave then(). En primer lugar, se suele validar el código de estado de la respuesta:

.then()
.statusCode(200)

A continuación, podemos proceder a extraer el objeto de respuesta:

.extract()
.response();

y validar algunas de sus propiedades:

Assert.assertEquals(responseFirstUser.jsonPath().getString("name"), "Leanne Graham");
Assert.assertEquals(responseFirstUser.jsonPath().getString("email"), "Sincere@april.biz");

En cuanto a la generación de informes, REST-Assured no proporciona una herramienta de generación de informes integrada. Por lo tanto, es necesario utilizar una biblioteca de informes externa adecuada, como Allure Report.

Karate vs REST-Assured

Bueno, ahora es el momento de comparar dos herramientas dadas y decidir cuál elegir para nuestras necesidades específicas. Vamos a comparar su rendimiento para el escenario de prueba simple mencionado anteriormente:

Karate vs. REST-Assured: Pruebas automatizadas de API con Java
Karate vs. REST-Assured: Pruebas automatizadas de API con Java

Como podemos ver, Karate tarda mucho menos tiempo en ejecutarse que REST-Assured en el caso de un único escenario. Sin embargo, al considerar múltiples escenarios (es decir, todo el ámbito de la prueba), cabe esperar que la diferencia no sea tan significativa.

La comparación de los dos marcos basada en otros criterios principales se presenta en la tabla siguiente:

Karate
REST-Assured

Sintaxis BDD

Karate

REST-Assured

Lenguaje de script de prueba

Karate

Karate-Script (Gherkin)

REST-Assured

Java

Validar toda la respuesta JSON

Karate

REST-Assured

No (se necesita una biblioteca Java adicional)

Ejecutor de pruebas

Karate

Opcional (JUnit, TestNG)

REST-Assured

Obligatorio (JUnit, TestNG)

Capacidad de reintento

Karate

REST-Assured

No (se necesita una biblioteca Java adicional)

Herramienta de informes

Karate

Integrada en

REST-Assured

Herramienta externa necesaria (Allure Report, etc.)

Leer archivo

Karate

REST-Assured

No (se necesita una biblioteca Java adicional)

Pruebas de rendimiento

Karate

Sí (es posible reutilizar las pruebas de Karate pruebas de Gatling)

REST-Assured

No

Tanto Karate como REST-Assured tienen sus puntos fuertes y débiles. En general, Karate tiene un mayor número de herramientas integradas en comparación con REST-Assured. Esto significa que puede empezar a escribir pruebas sin dedicar tiempo adicional a configurar bibliotecas externas. Además, Karate utiliza un lenguaje de escritura de pruebas sencillo y directo, lo que lo hace adecuado para equipos con poca experiencia en Java. Si está satisfecho con los informes estándar de Karate y no quiere invertir tiempo en configurar informes personalizados, puede ser una mejor opción.

Por otro lado, REST-Assured requiere una sólida formación en Java por parte del equipo de automatización de la garantía de calidad y el uso de bibliotecas adicionales. Sin embargo, en el caso de API complejas y muy personalizadas, REST-Assured puede ser una mejor opción. Escribir pruebas directamente en Java puede ser más fácil en estos casos.

REST-Assured también permite el uso de librerías como Hamcrest matchers, proporcionando más opciones para validación adicional en escenarios específicos. Si prefiere utilizar BDD y las definiciones de pasos preparadas previamente por Karate no satisfacen sus necesidades, REST-Assured puede utilizarse junto con una herramienta BDD externa como Cucumber.

Reflexiones finales

En conclusión, cabe destacar que tanto Karate como REST-Assured son herramientas desarrolladas activamente y bien documentadas. En última instancia, la elección entre Karate y REST-Assured debería basarse en factores como la complejidad de su API, el nivel de experiencia en Java de su equipo, la necesidad de opciones específicas de validación o personalización y su enfoque de pruebas preferido (por ejemplo, BDD).

Con la información proporcionada anteriormente, puede tomar una decisión informada sobre qué herramienta se adapta mejor a sus necesidades específicas. Le deseamos buena suerte.