Tutorial: cómo escribir pruebas con Vapor 2

En este tutorial, le mostraré cómo probar sus rutas en función del resultado del CRUD-Tutorial que escribí anteriormente. Si desea hacer el Tutorial CRUD primero y volver más tarde, puede encontrarlo aquí. Si desea omitir el CRUD-Tutorial, puede clonar el resultado aquí y comenzar de inmediato !

Puede encontrar el resultado de este tutorial de prueba en github: aquí.

1. Estructura del proyecto

Deberías tener una estructura de proyecto como esta:

prueba-ejemplo /
├── Package.swift
├── Fuentes /
│ ├── Aplicación /
│ │ ├── Config + Setup.swift
│ │ ├── Droplet + Setup.swift
│ │ ├── Routes.swift
│ │ └── Modelos /
│ │ └── User.swift
│ └── Ejecutar /
├── Pruebas /
│ └── Pruebas de aplicaciones /
│ ├── UserRequestTest.swift
│ └── Utilities.swift
├── Config /
├── Público /
├── Dependencias /
└── Productos /

Si ha clonado el repositorio de crud-tutorial, ya tendrá el archivo UserRequestTest.swift, en este caso elimine todo el código que contiene.

Si creó el proyecto crud siguiendo el tutorial crud, tendrá una estructura de proyecto como esta:

prueba-ejemplo /
├── Package.swift
├── Fuentes /
│ ├── Aplicación /
│ │ ├── Config + Setup.swift
│ │ ├── Droplet + Setup.swift
│ │ ├── Routes.swift
│ │ └── Modelos /
│ │ └── User.swift
│ └── Ejecutar /
├── Pruebas /
│ └── Pruebas de aplicaciones /
│ ├── PostControllerTests.swift
│ ├── RouteTests.swift
│ └── Utilities.swift
├── Config /
├── Público /
├── Dependencias /
└── Productos /

En este caso, eliminar (mover a la papelera)
• PostControllerTests.swift
• RouteTests.swift
y crea un archivo vacío llamado
• UserRequestTest.swift

prueba-ejemplo /
├── Package.swift
├── Fuentes /
│ ├── Aplicación /
│ │ ├── Config + Setup.swift
│ │ ├── Droplet + Setup.swift
│ │ ├── Routes.swift
│ │ └── Modelos /
│ │ └── User.swift
│ └── Ejecutar /
├── Pruebas /
│ └── Pruebas de aplicaciones /
│ ├── PostControllerTests.swift <- ELIMINAR
│ ├── RouteTests.swift <- ELIMINAR
│ ├── UserRequestTest.swift <- CREAR
│ └── Utilities.swift
├── Config /
├── Público /
├── Dependencias /
└── Productos /

2. Prueba: se crea el usuario

Pruebas internas / AppTests / UserRequestTest.swift escribir:

importar vapor
importar HTTP
importar XCTest
// se necesita importar la aplicación para guardar al usuario directamente como 'probar usuario (nombre de usuario: "Hero", edad: 23) .save ()'
Aplicación de importación @testable
clase UserRequestTest: TestCase {
  // obteniendo una instancia de nuestro drop con nuestra configuración
  dejar caer = probar! Droplet.testable ()
  func testThatUserGetsCreated () arroja {
    /// MARCA: PREPARANDO
    let un = "Tim", edad = 21
    let user = User (nombre de usuario: un, age: age)
  
    deja que json = intente user.makeJSON ()
    let reqBody = try Body (json)
    /// MARCA: PRUEBAS
    let req = Request (método: .post, uri: "/ user", encabezados: ["Content-Type": "application / json"], body: reqBody)
    let res = intente drop.testResponse (a: req)
    // la respuesta es 200
    res.assertStatus (es: .ok)
    // la respuesta de prueba es json
    guard let resJson = res.json else {
      XCTFail ("Error al obtener json de res: \ (res)")
      regreso
    }
    intente res.assertJSON ("id", pasa: {jsonVal en jsonVal.int! = nil})
    intente res.assertJSON ("nombre de usuario", igual a: un)
    intente res.assertJSON ("edad", es igual a: edad)
    /// MARK: LIMPIEZA
    guard let userId = resJson ["id"] ?. int, let userToDelete = intente User.find (userId) else {
      XCTFail ("El error no pudo convertir la identificación a int O no se pudo encontrar al usuario con la identificación de la respuesta: \ (res)")
      regreso
    }
    pruebe userToDelete.delete ()
  }
}

Permítanme explicar brevemente (además de los comentarios) lo que hace el código anterior. He desarrollado un patrón personal para estructurar las funciones de prueba:

func testThatUserGetsCreated () arroja {
  /// MARCA: PREPARANDO
  Esto marca el inicio del área donde preparo todos los datos que necesito para probar
  /// MARCA: PRUEBAS
  Esto marca el inicio del área donde realmente pruebo
  /// MARK: LIMPIEZA
  Esto marca el inicio del área donde limpio los datos eventualmente creados después de realizar las pruebas.
}

Queremos probar si nuestra ruta / usuario cuando se dispara con una solicitud POST que envía un JSON válido realmente está creando un usuario.

FUNCIÓN:
Descubrí que nombrar la función después de lo que hacen es muy útil y expresiva, por eso lo llamamos testThatUserGetsCreated ().

PREPARANDO:
En esta área estamos creando dos variables un (nombre de usuario) y edad (significa edad ). Inicializamos a nuestro usuario con estas variables y hacemos un objeto JSON con él. Inicializamos un cuerpo con el objeto JSON y eso es todo.

PRUEBAS:
Creamos un objeto de solicitud que pasa el método http, la url, el encabezado y el cuerpo que necesitamos para la ruta. Al disparar, intente drop.testResponse (to: req) nuestra solicitud se ejecuta y guardamos el resultado en la variable res.
Ahora podemos probar si la respuesta contiene lo que definimos en la ruta para regresar después de crear con éxito un usuario.

Definimos que la ruta devuelve al usuario creado como JSON.

Entonces verificamos con guardia si la respuesta contiene json. Si no, sabemos que algo salió mal, lo que arroja un XCTFail. Luego verificamos si el valor JSON en la clave id es del tipo int. Además, si el valor JSON en el nombre de usuario clave es igual a nuestra variable un y si el valor JSON en la edad clave es igual a nuestra variable edad. Si todo pasa, genial, ¡vamos a limpiar!

LIMPIAR:
Como el usuario se creó con éxito, tendremos una entrada en nuestra base de datos. Creo que las pruebas deberían dejar los lugares mejor de lo que los encontraron
Por lo tanto, convertimos el valor JSON en la identificación de la clave en un int e intentamos encontrar al usuario con la identificación. Si tenemos al usuario, simplemente ejecutamos delete () en él y terminamos

3. Ejecute nuestra primera prueba

Hay varias formas de ejecutar su prueba y todas son geniales. En este tutorial usaremos la caja de herramientas de vapor. Ejecute en su terminal en el directorio de su proyecto:

prueba de vapor

¡Le mostrará una bola genial yendo y viniendo tomando unos segundos y luego su prueba pasará! Whoop Whoop!

Sugerencia: si desea una salida más detallada, vaya y ejecute en su lugar: prueba rápida

4. Prueba: el usuario es leído

Esta función es más pequeña y como sabes lo que significa, aquí está el código

importar vapor
importar HTTP
importar XCTest
// se necesita importar la aplicación para guardar al usuario directamente como 'probar usuario (nombre de usuario: "Hero", edad: 23) .save ()'
Aplicación de importación @testable
clase UserRequestTest: TestCase {
  // obteniendo una instancia de nuestro drop con nuestra configuración
  dejar caer = probar! Droplet.testable ()
  func testThatUserGetsCreated () arroja {
    ...
  }
  func testThatUserGetsReturned () arroja {
    /// MARCA: PREPARANDO
    let un = "Elon", edad = 31
    let user = User (nombre de usuario: un, age: age)
    // crear usuario manualmente ya que queremos probar para obtenerlo
    intente user.save ()
    guard let userId = user.id?.int else {
      XCTFail ("Error al convertir el ID de usuario a int")
      regreso
    }
    /// MARCA: PRUEBAS
    let req = Request (método: .get, uri: "/ user / \ (userId)")
    let res = intente drop.testResponse (a: req)
    res.assertStatus (es: .ok)
    intente res.assertJSON ("nombre de usuario", igual a: un)
    /// MARK: LIMPIEZA
    intente user.delete ()
  }
}

De nuevo puedes ir a por:

prueba de vapor

O lo que prefiero porque verá todas las funciones que se ejecutan cuando ejecuta sus pruebas:

prueba rápida

5. Prueba: el usuario se actualiza

Hablar es barato. Muéstrame el código.

importar vapor
importar HTTP
importar XCTest
// se necesita importar la aplicación para guardar al usuario directamente como 'probar usuario (nombre de usuario: "Hero", edad: 23) .save ()'
Aplicación de importación @testable
clase UserRequestTest: TestCase {
  // obteniendo una instancia de nuestro drop con nuestra configuración
  dejar caer = probar! Droplet.testable ()
  func testThatUserGetsCreated () arroja {
    ...
  }
  func testThatUserGetsReturned () arroja {
    ...
  }
  func testThatUserGetsUpdated () arroja {
    /// MARCA: PREPARANDO
    let un = "Steve", edad = 37
    let user = User (nombre de usuario: un, age: age)
    intente user.save ()
    /// MARCA: PRUEBAS
    guard let userId = user.id?.int else {
      XCTFail ("Error al convertir el ID de usuario a int")
      regreso
    }
    // cambiar datos
    let newUn = "Craig"
    user.username = newUn
    deja que json = intente user.makeJSON ()
    let reqBody = try Body (json)
    // el usuario de prueba se actualiza
    let updateUserReq = Request (método: .put, uri: "/ user / \ (userId)", encabezados: ["Content-Type": "application / json"], body: reqBody)
    deje que updateUserRes = intente drop.testResponse (a: updateUserReq)
    updateUserRes.assertStatus (es: .ok)
    pruebe updateUserRes.assertJSON ("nombre de usuario", igual a: newUn)
    /// MARK: LIMPIEZA
    intente user.delete ()
  }
}

¿Sabes qué ejecutar en la línea de comando ?

Sugerencia: prueba rápida o prueba de vapor

6. Prueba: el usuario es eliminado

Siento que no se necesitan palabras ya que también comento mi código. Pero si siente que faltan explicaciones, ¡hágamelo saber definitivamente en la sección de comentarios!

importar vapor
importar HTTP
importar XCTest
// se necesita importar la aplicación para guardar al usuario directamente como 'probar usuario (nombre de usuario: "Hero", edad: 23) .save ()'
Aplicación de importación @testable
clase UserRequestTest: TestCase {
  // obteniendo una instancia de nuestro drop con nuestra configuración
  dejar caer = probar! Droplet.testable ()
  func testThatUserGetsCreated () arroja {
    ...
  }
  func testThatUserGetsReturned () arroja {
    ...
  }
  func testThatUserGetsUpdated () arroja {
    ...
  }
  func testThatUserGetsDeleted () arroja {
    /// MARCA: PREPARANDO
    let user = User (nombre de usuario: "Jony", edad: 23)
    intente user.save ()
    guard let userId = user.id?.int else {
      XCTFail ("Error al convertir el ID de usuario a int")
      regreso
    }
    /// MARCA: PRUEBAS
    let req = Request (método: .delete, uri: "/ user / \ (userId)", encabezados: ["Content-Type": "application / json"], body: Body ())
    let res = intente drop.testResponse (a: req)
    res.assertStatus (es: .ok)
    intente res.assertJSON ("tipo", es igual a: "éxito")
  }
}

¡Y ahora el golpe final en tu terminal!

prueba rápida

o lo sabes:

prueba de vapor

Felicidades! ¡Implementaste con éxito pruebas con Vapor !

Muchas gracias por leer! Si tiene alguna sugerencia o mejora, ¡hágamelo saber! ¡Me encantaría saber de ti!

Twitter / Github / Instagram