Advanced Guides
Integrar pruebas avanzadas en funciones Parse Cloud Code
36 min
cómo integrar pruebas en tus funciones de parse cloud code introducción esta es una guía escrita por https //github com/considine , nuestro escritor invitado y desarrollador principal en https //koptional com/ el tutorial cubre cómo configurar pruebas automatizadas para tu cloud code de back4app hablaremos brevemente sobre cómo mover parte de tu código de cliente de parse a la nube, y luego sobre cómo integrar tu proyecto con un ecosistema de pruebas también puedes consultar el https //github com/back4app/template cloud code unit test directamente para una versión funcional objetivos esperamos combinar los aspectos robustos y escalables de las pruebas automatizadas con el entorno amigable para desarrolladores de parse al aprovechar cloud code, quizás una característica subestimada de parse, los desarrolladores pueden continuar iterando rápidamente su código y estar seguros de que el software funcionará como se espera https //en wikipedia org/wiki/test driven development es un campo inmenso; en lugar de hablar filosóficamente sobre las pruebas, pasaremos por una implementación y hablaremos sobre algunas estrategias (como el stubbing, por ejemplo) requisitos previos para completar este tutorial, necesitas una aplicación en back4app sigue el https //www back4app com/docs/get started/new parse app para aprender cómo crear una aplicación en back4app back4app command line configurado con el proyecto sigue el https //www back4app com/docs para aprender cómo configurar el código en la nube para un proyecto npm instalado en tu línea de comandos nota esta biblioteca utilizará el https //www promisejs org/ , que no debería ser demasiado complicado creemos un backend básico para redes sociales ¡ok! imagina una aplicación de redes sociales que incluya un modelo de perfil junto con el modelo de usuario para algunas aplicaciones, puedes colocar la información del perfil en el modelo de usuario, aunque en muchos casos esto no es eficiente; a menudo necesitarás separar las preocupaciones de autorización/autenticación del contenido del usuario, y así mantener dos modelos diferentes en este tutorial, implementaremos una función que gestiona la creación de usuarios y perfiles de esta manera, colocando una carga mínima en el cliente ¡comencemos! 1\ definiendo nuestras funciones esto asume que tienes un proyecto de back4app creado y la herramienta de línea de comandos instalada (ver requisitos previos) para ejemplos de código frontend, esta guía se referirá a la sintaxis del sdk de javascript de parse por simplicidad cuando alguien se registre en esta aplicación, se debe crear un perfil y acoplarlo al objeto de usuario la función de registro en muchas aplicaciones de parse, crearás el usuario con la siguiente sintaxis 1 var user = new parse user(); 2 user set("username", "my name"); 3 user set("password", "my pass"); 4 user set("email", "email\@example com"); en nuestro caso, también nos gustaría inicializar un perfil y apuntarlo al objeto usuario parse server 3 x 1 try { 2 await user signup(null, {usemasterkey true}); 3 let profile = parse object extend("profile"); 4 let profile = new profile({ 5 firstname params firstname, 6 lastname params lastname, 7 user user 8 }) 9 return profile save(null, {usemasterkey true}); 10 } catch (err){ 11 return (err message); 12 } parse server 2 x 1 user signup(null, { 2 success function (newuser) { 3 var profile = parse object extend("profile"); 4 var profile = new profile(); 5 profile set("firstname", "john"); 6 profile set("lastname", "smith"); 7 profile set("user", newuser); 8 profile save(); 9 }, 10 error function (err) { 11 // handle error 12 } 13 }) podrías acortar esa sintaxis a algo como esto parse server 3 x 1 let user = new parse user({ 2 username params username, 3 password params password, 4 email params email 5 }); 6 7 try { 8 await user signup(null, {usemasterkey true}); 9 let profile = parse object extend("profile"); 10 let profile = new profile({ 11 firstname params firstname, 12 lastname params lastname, 13 user user 14 }) 15 return profile save(null, {usemasterkey true}); 16 } catch (err){ 17 return (err message); 18 } parse server 2 x 1 var user = new parse user({ 2 username params username, 3 password params password, 4 email params email 5 }); 6 user signup(null) 7 then((newuser) => { 8 var profile = parse object extend("profile"); 9 var profile = new profile({ 10 "firstname" "john", 11 "lastname" "smith", 12 "user" newuser 13 }); 14 return profile save(); 15 }) desafortunadamente, esto aún implica hacer dos solicitudes separadas al servidor parse, lo cual es ineficiente para un frontend; es prudente evitar flujos de comunicación cliente servidor de múltiples pasos cuando sea posible además, en cuanto a la seguridad, el código anterior está poniendo el proceso de creación en manos de un cliente, lo cual nunca es inteligente nos gustaría evitar que la integridad de nuestros datos dependa de que un cliente complete correctamente todos los pasos de un flujo podrían, por ejemplo, enviar una solicitud personalizada que cree un usuario sin perfil, corrompiendo los datos persistentes de la aplicación ¿por qué no hacer todo esto en un solo paso utilizando código en la nube? puede prevenir la sobrecarga del código del frontend y asegurar que el cliente no esté realizando trabajos innecesarios/inseguros! aquí está lo que queremos hacer en su lugar desde el cliente para el registro 1 parse cloud run('signupuser', 2 { 3 username 'myname', 4 password "mypass", 5 email "email\@example com", 6 firstname "john", 7 lastname "smith" } 8 ) then(function(newuser) { 9 10 }); parse también define para http //docs parseplatform org/cloudcode/guide/#beforesave triggers triggers, permitiendo la creación del perfil cuando el usuario se registra sin embargo, al usar una función, podemos pasar intuitivamente los atributos firstname y lastname que el perfil utilizará función de registro de código en la nube ¡comencemos! muévete a tu directorio de proyecto que está sincronizado con back4app (consulta los requisitos previos si no sabes qué significa esto) asumiremos la siguiente estructura 1 /cloud 2 /cloud/main js en nuestro caso, al inicializar, elegimos ‘nube’ como nuestro nombre de directorio tu directorio puede llamarse como quieras parse server 3 x main js 1 parse cloud define("signuserup", async(request) => { 2 // make sure the necessary parameters are passed first 3 let params = request params; 4 if (!params username || !params email || !params password || !params firstname || !params lastname) 5 throw new error("missing parameters need username, email, password, firstname, & lastname"); 6 7 // execute the signup flow 8 let user = new parse user({ 9 username params username, 10 password params password, 11 email params email 12 }); 13 14 try { 15 await user signup(null, {usemasterkey true}); 16 let profile = parse object extend("profile"); 17 let profile = new profile({ 18 firstname params firstname, 19 lastname params lastname, 20 user user 21 }) 22 return profile save(null, {usemasterkey true}); 23 } catch (err){ 24 return (err message); 25 } 26 }); parse server 2 x main js 1 parse cloud define("signuserup", function(request, response) { 2 // make sure the necessary parameters are passed first 3 var params = request params; 4 if (!params username || !params email || !params password || !params firstname || !params lastname) 5 return response error("missing parameters need username, email, password, firstname, & lastname"); 6 7 // execute the signup flow 8 var user = new parse user({ 9 username params username, 10 password params password, 11 email params email 12 }); 13 user signup(null, {usemasterkey true}) 14 then((newuser) => { 15 var profile = parse object extend("profile"); 16 var profile = new profile({ 17 firstname params firstname, 18 lastname params lastname, 19 user newuser 20 }) 21 return profile save(null, {usemasterkey true}); 22 }) 23 then((prof) => response success(prof)) 24 catch((e) => { 25 response error(e message); 26 }) 27 }); puedes notar que se pasa la opción ‘usemasterkey’; esto permite que el código en la nube supere cualquier rol o acl que pueda estar en su lugar dado que el cliente no toca este código, no hay riesgo de que secuestren nuestro servidor sin embargo, ¡ten cuidado con esta bandera! en caso de que no sea obvio por qué esto podría ser preferible a colocar esta funcionalidad en el código del cliente, aquí hay algunas ventajas descarga la computación al servidor en lugar de al dispositivo define explícitamente la funcionalidad de un proceso más fácil de crear funciones a prueba de fallos le da al cliente una interfaz intuitiva esto previene la posibilidad de que un cliente ‘haga a medias’ un proceso 2\ refactorizando nuestra estructura de directorios genial, hemos creado dos funciones en la nube obviamente podríamos probar estas funciones ejecutándolas y revisando el panel de control de parse, pero eso no es escalable ni eficiente en su lugar, queremos crear pruebas automatizadas específicamente para los métodos que se pueden ejecutar continuamente así que separaremos un poco nuestro código moveremos las funciones que creamos en main js a un nuevo archivo llamado cloud functions js (en el mismo directorio) luego importaremos estas funciones en main, y las vincularemos a las definiciones de funciones en la nube la idea es desacoplar las funciones de la interfaz en la nube para que podamos probarlas sin enviar solicitudes http de manera ineficiente esto tendrá mucho sentido a medida que creemos el conjunto de pruebas crear el archivo de funciones \# recuerda, el directorio 'cloud' fue determinado \# cuando inicializamos el directorio con nuestro proyecto back4app \# consulta los requisitos previos si esto no tiene sentido touch /cloud/cloud functions js es posible que sepas que puedes usar ‘require’ en node js para importar funciones, objetos y variables de otros archivos por lo tanto, definiremos funciones correspondientes a la función en la nube de parse que creamos en el paso 1 un punto que puede resultar confuso es que las funciones que estamos definiendo serán funciones de retorno , que luego pueden ser conectadas a la definición de la nube de parse puede parecer extraño usar una función para devolver una función, pero esto nos dará el poder de cambiar los servidores de parse más adelante cuando estemos escribiendo nuestras pruebas es posible que hayas notado que puedes usar el objeto parse en tu código en la nube, sin tener que definirlo o importarlo esto se debe a que el servidor que ejecuta este código agrega parse automáticamente sin embargo, si queremos ejecutar pruebas en las funciones localmente, no tenemos acceso a una instancia de hecho, nos gustaría proporcionar nuestra propia instancia que corresponda a un servidor de prueba de parse, donde no hay problema en que se creen o eliminen datos así que cada función aceptará 'parse' como un parámetro y devolverá las funciones en la nube parse server 3 x cloud functions js 1 // cloud functions js 2 module exports signupuser = function(parse) { 3 return async(request) => { 4 // copied from main js 5 // make sure the necessary parameters are passed first 6 let params = request params; 7 if (!params username || !params email || !params password || !params firstname || !params lastname) 8 throw new error("missing parameters need username, email, password, firstname, & lastname"); 9 10 // execute the signup flow 11 let user = new parse user({ 12 username params username, 13 password params password, 14 email params email 15 }); 16 17 try { 18 await user signup(null, {usemasterkey true}); 19 let profile = parse object extend("profile"); 20 let profile = new profile({ 21 firstname params firstname, 22 lastname params lastname, 23 user user 24 }) 25 return profile save(null, {usemasterkey true}); 26 } catch (err){ 27 return (err message); 28 } 29 } 30 } parse server 2 x cloud functions js 1 // cloud functions js 2 module exports signupuser = function(parse) { 3 return function (request, response) { 4 // copied from main js 5 // make sure the necessary parameters are passed first 6 var params = request params; 7 if (!params username || !params email || !params password || !params firstname || !params lastname) 8 return response error("missing parameters need username, email, password, firstname, & lastname"); 9 // execute the signup flow 10 var user = new parse user({ 11 username params username, 12 password params password, 13 email params email 14 }); 15 user signup(null, {usemasterkey true}) 16 then((newuser) => { 17 var profile = parse object extend("profile"); 18 var profile = new profile({ 19 firstname params firstname, 20 lastname params lastname, 21 user newuser 22 }) 23 return profile save(null, {usemasterkey true}); 24 }) 25 then((prof) => response success(prof)) 26 catch((e) => { 27 response error(e message); 28 }) 29 } 30 } en main js, elimina todo lo anterior importa la función en la nube y vincula la función a la definición de la función en la nube así 1 // main js 2 var cloudfunctions = require(" /cloud functions"); 3 // note that we are injecting the parse instance, which is automatically supplied in the 4 // context of parse cloud code, but not on local tests 5 parse cloud define("signuserup", cloudfunctions signupuser(parse)); ¡genial! no hemos cambiado la funcionalidad en absoluto desde el paso 1, pero hemos desacoplado la función del código en la nube ¡en el siguiente paso crearemos una prueba unitaria! 3\ crear la suite de pruebas para nuestra suite de pruebas, utilizaremos https //jasmine github io/ , el popular marco de pruebas sin embargo, nuestro código hasta ahora es completamente ajeno a nuestras pruebas, por lo que puedes usar cualquier marco o plataforma que prefieras instalemos jasmine y jasmine node (una integración de jasmine y nuestro entorno de node js) $ npm install jasmine jasmine node save dev ahora instalemos dos bibliotecas que usará nuestro conjunto de pruebas usará el sdk de parse para conectarse a un servidor parse falso y la biblioteca de eventos para simular el objeto de solicitud $ npm install parse events save dev ahora, usando la utilidad jasmine, inicialicemos nuestro directorio de pruebas $ /node modules/jasmine/bin/jasmine js init si lo prefieres, puedes instalar jasmine globalmente con $ npm install g jasmine $ npm install g jasmine , luego puedes inicializar con este $ jasmine init $ jasmine init esta guía asumirá que no instalas jasmine globalmente, aunque se recomienda si lo haces, puedes reemplazar todas las instancias de ‘/node modules/jasmine/bin/jasmine js’ simplemente con ‘jasmine’ esto debería crear un directorio llamado spec, que a su vez incluye una carpeta de soporte que contiene información de configuración para jasmine por defecto, jasmine sabe buscar archivos que terminen en la extensión “ spec js”, así que nombraremos nuestras pruebas en consecuencia crea el archivo para nuestra primera prueba unitaria $ # en el directorio /spec $ touch signup user spec js' agrega un directorio de utilidades con dos archivos que ayudarán con nuestras pruebas $ # en el directorio /spec $ touch utils/purge parse table js $ touch utils/response stub js finalmente, crea un archivo de constantes en el mismo directorio la utilidad para este archivo se explicará más adelante $ # en el directorio /spec $ touch constants js así es como debería verse ahora tu directorio ├── cloud │ ├── cloud functions js │ ├── main js ├── node modules ├── spec │ ├── support │ │ ├── jasmine json │ ├── utils │ │ ├── purge parse table js │ │ ├── response stub js │ ├── signup user spec js │ ├── constants js 4\ intercambiando en un servidor parse de prueba pruebas alrededor de parse dado que nuestros métodos involucran un servidor parse, queremos poder probar esa interacción hay dos formas de hacerlo a podemos "simular" el objeto sdk de parse, definiendo un objeto que implemente la misma interfaz luego simplemente pasamos ese objeto como parámetro a nuestros métodos en la nube eso podría verse algo así 1 var parsestub = { 2 // make sure all used methods and properties are defined 3 user function () { 4 // constructor function 5 this set = function (key, val) { 6 // logic here to implement the parse object set 7 } 8 } 9 } 10 signupuser(parsestub); // returns cloud function that we can test b otro enfoque es configurar un servidor parse real que solo sirva para datos de prueba esto implicará la lenta capa http que utiliza parse, pero también nos permitirá probar los datos en la base de datos en nuestras pruebas necesitaríamos importar el sdk de parse y configurarlo con un servidor de prueba los dos lugares que se pueden simular al probar el código en la nube a ) simular un sdk de parse que no hará solicitudes http, o b ) intercambiar por una implementación de base de datos de prueba ninguno de estos enfoques es la respuesta "correcta" depende de lo que estés tratando de probar simular la interfaz para el sdk de parse (incluso solo las partes que estamos usando) es mucho trabajo además, vamos a probar la persistencia de los datos después de guardarlos en este ejemplo, así que utilizaremos el segundo enfoque vamos crear un servidor parse de prueba en back4app obtener el id de la aplicación y la clave maestra y guardarlos en nuestro archivo de constantes inicializar el sdk de parse en nuestro archivo de especificaciones, para que nuestra prueba use el servidor de prueba eres bienvenido a ejecutar un https //github com/parse community/parse server local para tus pruebas simplemente crearemos otra aplicación de back4app en nuestro panel si necesitas un repaso sobre cómo provisionar otro servidor de back4app, dirígete al https //www back4app com/docs/get started/new parse app llama a tu aplicación como quieras, aunque podría ser prudente usar algo como testbackend luego simplemente obtén el id de la aplicación y la clave maestra desde dashboard > configuración de la aplicación > seguridad y claves ahora guarda estos tokens en nuestro archivo de constantes así 1 // /spec/constants js 2 // paste in your app id and master key where the strings are 3 module exports = { 4 application id "paste your application key here", 5 master key "paste your master key here" 6 } ¡no pongas el id de aplicación y la clave maestra de tu aplicación de producción! estaremos eliminando datos, y hacerlo pondrá en riesgo la pérdida de datos 5\ utilidades de prueba las funciones en la nube se pasan como parámetros en los objetos de solicitud y respuesta de express el servidor crea automáticamente estos parámetros cuando se ejecutan en la nube, así que para nuestros entornos de prueba debemos crear dobles este caso es más fácil cuando se llama a una función en la nube, se pasan datos; en nuestro caso, se pasan la información del perfil y del usuario cada argumento que se proporciona es accesible desde la propiedad request params así que si llamamos a una función en la nube como 1 // client code, calling parse function 2 parse cloud run('fakefunction', 3 { 4 data1 'i am data1', 5 data2 { 6 prop "nested property" 7 } 8 } 9 ); entonces la propiedad request params contendrá los datos pasados 1 // server code, running the parse function 2 console log(request params); 3 // { 4 // data1 'i am data1', 5 // data2 { 6 // prop "nested property" 7 // } 8 // } suficientemente simple, para nuestras pruebas, al llamar a nuestra función en la nube, el primer argumento debería ser de la forma 1 { 2 params { 3 username 'testuser', 4 firstname "john", 5 // the rest of the arguments 6 } 7 } por lo tanto, no necesitamos crear un objeto simulado especial en este caso el objeto de respuesta permite que el código en la nube envíe una respuesta http al cliente que representa ya sea un éxito o un fracaso nos gustaría saber cómo se llama al invocar la función en la nube a continuación hay un https //msdn microsoft com/en us/library/ff650441 aspx que permitirá a nuestra prueba determinar si la invocación fue exitosa o no si esto es confuso, no te preocupes, simplemente colócalo en tu archivo /spec/utils/response stub js 1 // /spec/utils/response stub js 2 const eventemitter = require('events'); 3 / 4 wrapper around response stub simplifies testing cloud functions that 5 employ a response parameter 6 / 7 function responsestub () { 8 this responselistener = new eventemitter(); 9 this responsestub = {}; 10 / 11 success method that cloud functions expect 12 / 13 this responsestub success = (resp) => { 14 this responselistener emit("success", resp); 15 } 16 / 17 error method that cloud functions expect 18 / 19 this responsestub error = (resp) => { 20 this responselistener emit("error", resp); 21 } 22 / 23 listens for errors and successes from stub and returns promise that resolves or rejects accordingly 24 / 25 this resolver = new promise((resolve, reject) => { 26 this responselistener on("success", (resp) => resolve(resp)); 27 this responselistener on("error", (err) => reject(err)); 28 }); 29 } 30 31 / 32 reeturns stub to feed to cloud function 33 / 34 responsestub prototype getstub = function () { 35 return this responsestub; 36 } 37 38 / 39 returns promise that will indicate the success or failure 40 / 41 responsestub prototype oncomplete = function () { 42 return this resolver; 43 } 44 45 module exports = responsestub; en resumen, esta función constructora de javascript proporcionará una manera para que nuestra prueba pase un objeto de respuesta que indica mediante la resolución / rechazo de la promesa si la función en la nube habría devuelto un éxito o un error limpiando la base de datos obviamente no queremos que nuestra base de datos de parse de prueba retenga lo que se acumula durante una prueba definamos una utilidad para limpiar las tablas de la base de datos, que se puede llamar antes (o después) de los casos de prueba agrega lo siguiente a ‘spec/utils/purge parse table js’ 1 // spec/utils/purge parse table js 2 / 3 removes all rows from the parse database 4 @param {string} tablename the name of the parse table to be purged 5 @return {promise} promise to destroy each item in the table 6 / 7 module exports = function (parse) { 8 return (tablename) => { 9 var tablequery; 10 if (tablename === "user") 11 tablequery = new parse query(parse user); 12 else tablequery = new parse query(tablename); 13 return tablequery find({usemasterkey true}) then((items) => { 14 var destroyqueue = \[]; 15 for (var i=0; i\<items length; i++) { 16 destroyqueue push(items\[i] destroy({usemasterkey true})); 17 } 18 return promise all(destroyqueue) catch((e) => {console log("error destroying " + e message)}); 19 }); 20 } 21 } después de definir esta función, es un buen momento para recordarte que asegures que tu spec/utils/constants js esté configurado para tu aplicación de parse de prueba, no para tu aplicación de parse de producción esto eliminará datos, así que por favor confirma que esta es la base de datos vacía que creaste arriba esta función acepta nuestro sdk de parse configurado y devuelve otra función la función devuelta acepta un nombre de tabla y elimina todos los datos de la tabla de parse correspondiente de nuevo, la idea de devolver una función puede parecer extraña, pero permite que la especificación de prueba configure el punto final de parse y luego haga referencia a una función que limpiará la tabla de ese punto final de parse ¡increíble! ¡ahora escribamos nuestra prueba! 6\ prueba que la función en la nube enviará un error si no se pasan los parámetros adecuados la función en la nube depende de que se incluyan ciertos parámetros y debería fallar si, por ejemplo, no se envió el ‘firstname’ asegurémonos estaremos editando nuestro archivo de prueba (¡finalmente!) spec/signup user spec js esto es lo que necesita suceder antes de las definiciones de prueba importar el sdk de parse nodejs importar nuestras constantes y configurar el sdk de parse para apuntar a nuestro servidor de prueba importar nuestra función en la nube importar nuestra utilidad de “purgar tabla” importar el objeto mock de respuesta que creamos lo siguiente será suficiente 1 // hook into your testing server 2 var parse = require('parse/node'); 3 var constants = require(" /constants"); 4 // head over to your parse dash board for your test server, and grab your keys swap out the strings with the place holders below 5 parse initialize(constants application key, null, constants master key); 6 // if you are running a localhost parse server, set the serverurl accordingly 7 parse serverurl = 'https //parseapi back4app com' 8 var signupuser = require(" /cloud/cloud functions") signupuser(parse); 9 var purgetable = require(" /utils/purge parse table")(parse); 10 var responsestub = require(" /utils/response stub"); ahora agreguemos los casos de prueba la https //jasmine github io/2 1/introduction puede ayudar a entender mejor la estructura, pero se ve así (tomado de la introducción) describe("una suite", () => { it("contiene una especificación con una expectativa", () => { expect(true) tobe(true); }); }); así que los bloques describe encapsulan suites de prueba, y los bloques ‘it’ representan casos y expectativas al pasar un parámetro a los bloques ‘it’, puedes ejecutar pruebas de manera asíncrona la prueba no se completará hasta que el parámetro sea invocado de esta manera it("no terminará hasta que se llame a done", (done) => { settimeout(() => { done(); }, 100); // 100 ms expect(x) tobe(y); }) esto es útil ya que una de nuestras pruebas utilizará http, por lo tanto, debe ejecutarse de manera asíncrona de esta manera, ya que usar http es un procedimiento no bloqueante en nodejs además, jasmine permite bloques especiales dentro de suites que pueden ejecutarse en diferentes puntos del ciclo de vida de las pruebas queremos eliminar todas las tablas antes de cada prueba, así que ejecutaremos el código de purga en el bloque beforeeach ¡suficiente charla, vamos a agregar algo de código! coloca el código a continuación en tu spec/signup user spec js, debajo de las importaciones que ya agregamos 1 //spec/signup user spec js 2 // imports above 3 describe("signupuser", ()=> { 4 beforeeach((done) => { 5 /// purge the user and profile tables, and then proceed 6 promise all(\[purgetable("user"), purgetable("profile")]) 7 catch((e) => fail(e)) 8 then(() => done()); 9 }); 10 it ("should reject a request to signup that does not contain all the parameters", (done) => { 11 var responsestub = new responsestub(); 12 responsestub oncomplete() 13 then(() => fail("should have failed due to invalid parameters")) 14 catch((e) => {}) 15 then(() => done()); 16 17 signupuser({ params {}}, responsestub getstub()); 18 19 }); 20 }); increíble, nuestra primera prueba está en marcha en el bloque beforeeach, purgamos las tablas de usuario y perfil luego se activa el primer caso de prueba verifica que pasar parámetros inválidos a la función signupuser hace que la función envíe un error utiliza el stub de respuesta para asegurarse de que la función finalmente fue rechazada debido a que ‘signupuser’ fallará, el bloque ‘then’ inicial en el stub no debería ser invocado ¡si lo es, entonces nuestra prueba falla! adelante, ejecuta la prueba usando lo siguiente $ /node modules/jasmine/bin/jasmine js spec/signup user spec js deberías ver la siguiente salida aleatorizado con semilla 24618 iniciado 1 especificaciones, 0 fallos terminado en 1 376 segundos aleatorizado con semilla 24618 (jasmine random=true seed=24618) 7\ una prueba sobre la persistencia de datos ¡espero que tengas una prueba más en ti! vamos a verificar que cuando nuestra función en la nube se ejecute correctamente, nuestra base de datos será como se espera existirá un perfil, con una referencia a un objeto usuario, ambos con los atributos esperados agrega el siguiente bloque a nuestro bloque de suite ‘describe’ existente 1 //spec/signup user spec js 2 // inside describe 3 it ("should signup a user, and also create a profile that contains a reference to the user", (done) => { 4 var responsestub = new responsestub(); 5 var stub = responsestub getstub(); 6 signupuser({ 7 params { 8 firstname "john", 9 lastname "smith", 10 email "jsmith\@example com", 11 username "jsmith1", 12 password "secretcatchphrase1" 13 }, 14 }, 15 stub 16 ); 17 responsestub oncomplete() 18 then((resp) => { 19 var profileq = new parse query("profile"); 20 profileq equalto("lastname", "smith"); 21 return profileq find({usemasterkey true}); 22 }) 23 // check to make sure the profile we retrieve is valid 24 then((profiles) => { 25 if (profiles length === 0) throw new error("no profile's found"); 26 expect(profiles\[0] get('firstname')) tobe("john"); 27 // get the corresponding user 28 return profiles\[0] get("user") fetch({usemasterkey true}) 29 }) 30 // check to make sure the user is what we expect 31 then((user) => { 32 expect(user getusername()) tobe("jsmith1"); 33 }) 34 catch((e) => { 35 console log(e) 36 fail(e); 37 }) 38 then(() => done()); 39 }); ok, esto es mucho, así que vamos a repasar lo que ocurre instanciamos un objeto de respuesta simulado, como en el primer caso de prueba luego ejecutamos signupuser con un doble de solicitud que contiene parámetros , así como el objeto de respuesta simulado (líneas 6 16) a continuación, este código escucha el método oncomplete del objeto simulado, que devolverá una promesa la promesa se rechazará si se llama a response error, y se resolverá si se llama a response success cualquier rechazo hará que la cadena de promesas salte al bloque catch por lo tanto, el método fail se coloca en el bloque catch, ya que la prueba debería fallar si la promesa se rechaza la respuesta de la promesa debería resolverse al objeto perfil una vez que se resuelve, consultaremos un perfil con el mismo apellido que creamos (líneas 19 21) luego, la prueba confirma que el ‘firstname’ del perfil es el mismo que pasamos (líneas 25 26) el siguiente bloque obtiene el objeto usuario asociado con el perfil los punteros de objeto parse se obtienen por separado, de ahí la necesidad de otro bloque de promesa finalmente, el código confirma que el usuario correspondiente tiene el nombre de usuario que se pasó a la función signupuser luego, la prueba finaliza adelante, ejecuta la suite una vez más adelante, ejecuta la prueba usando lo siguiente $ /node modules/jasmine/bin/jasmine js spec/signup user spec js deberías ver la siguiente salida aleatorizado con semilla 24618 iniciado 2 especificaciones, 0 fallos terminado en 2 876 segundos aleatorizado con semilla 24618 (jasmine random=true seed=24618) ¡increíble! escribimos algo de código en la nube e integramos un marco de pruebas conclusión si te perdiste en algún momento, o simplemente quieres el código para este ejemplo, dirígete al https //github com/back4app/template cloud code unit test sigue las instrucciones para descargar y ejecutar si algo no está claro, o no funciona, por favor contáctame a través de mi gmail, jackconsidine3 ¡espero que hayas disfrutado este tutorial y hayas ganado algo de conocimiento!