Probando tu JavaScript con Jasmine

Todos sabemos que deberíamos probar nuestro código, pero en realidad no lo hacemos. Creo que es justo decir que la mayoría de nosotros lo postergamos porque, nueve de cada diez veces, significa aprender otro concepto. En este tutorial, te presentaré un pequeño gran marco para probar tu código JavaScript con facilidad.

Por cierto, ¿sabía que un experto en Envato Studio puede corregir sus errores de JavaScript rápida y fácilmente??

ThemeManiac, por ejemplo, solucionará errores de Java o JavaScript o problemas de compatibilidad del navegador en su sitio web o aplicación web. Las correcciones se pueden completar muy rápido, según la complejidad y la información disponible. También puede reorganizar sus scripts y crear una experiencia de usuario completamente nueva. Ha completado más de 1,000 trabajos en Envato Studio, con el 99% de los clientes que lo recomiendan.


Paso 0: Entendiendo la BDD

Hoy vamos a aprender sobre el marco de prueba de Jasmine BDD. Pero primero nos detendremos aquí para un desvío, para hablar muy brevemente, sobre BDD y TDD. Si no estás familiarizado con estos acrónimos, representan Desarrollo impulsado por el comportamiento y Desarrollo guiado por pruebas. Estoy aprendiendo qué es cada uno de estos en la práctica y cómo son diferentes, pero aquí están algunas de las diferencias básicas:

BDD y TDD? representar Desarrollo impulsado por el comportamiento y Desarrollo guiado por pruebas.

TDD en su forma más simple es esto:

  1. Escribe tus pruebas
  2. Verlos fallar
  3. Hacerlos pasar
  4. Refactor
  5. Repetir

Eso es bastante fácil de entender, eh?

El BDD es un poco más complejo: como lo entiendo ahora mismo, no creo que usted o yo, como un solo desarrollador, podamos practicarlo completamente; Es más una cosa de equipo. Aquí están algunas de las prácticas de BDD:

  • Establecer los objetivos de las diferentes partes interesadas requeridas para implementar una visión.
  • Involucrar a las partes interesadas en el proceso de implementación a través del desarrollo de software externo.
  • Usar ejemplos para describir el comportamiento de la aplicación o de unidades de código.
  • Automatizando esos ejemplos para proporcionar retroalimentación rápida y pruebas de regresión

Para obtener más información, puede leer el extenso artículo de Wikipedia (del cual se tomaron esos puntos).

Todo esto para decir que, si bien Jasmine se anuncia a sí misma como un marco BDD, lo vamos a utilizar de una forma más TDD. Eso no significa que lo estemos usando mal, sin embargo. Una vez que hayamos terminado, ¿podrás probar tu JavaScript con facilidad? y espero que lo hagas!


Paso 1: Aprendiendo la sintaxis

Jasmine toma muchas señales de Rspec.

Si está familiarizado con Rspec, el de facto En el marco de BDD, verá que Jasmine toma muchas señales de Rspec. Las pruebas de jazmín son principalmente dos partes: describir bloques y eso bloques Veamos como funciona esto..

Veremos algunas pruebas más cercanas a la vida real en unas pocas, pero por ahora, lo haremos simple:

describe ('operador de adición de JavaScript', función () it ('agrega dos números juntos', función () espera (1 + 2) .toEqual (3);););

Ambos describir y eso Las funciones toman dos parámetros: una cadena de texto y una función. La mayoría de los marcos de prueba intentan leer lo más parecido posible al inglés, y puedes ver esto con Jasmine. Primero, note que la cadena pasó a describir y la cadena pasó a eso forme una oración (de tipo): "El operador de adición de JavaScript suma dos números". Luego, vamos a mostrar cómo.

Dentro de eso eso bloque, puede escribir todo el código de configuración que necesita para su prueba. No necesitamos ninguno para este simple ejemplo. Una vez que esté listo para escribir el código de prueba real, comenzará con el esperar Funciona, pasandolo lo que sea que estes probando. Observe cómo esto también forma una oración: esperamos que 1 + 2 sea igual a 3.?

Pero me estoy adelantando a nosotros mismos. Como he dicho, cualquier valor que pases esperar será probado. El método que llama, fuera del valor devuelto de esperar, será determinado por la prueba que se ejecuta. Este grupo de métodos se llama "emparejadores" y veremos varios de ellos hoy. En este caso, estamos utilizando el A igual Matcher, que verifica que el valor pasado a esperar y el valor pasado a A igual son el mismo valor.

Creo que estás listo para llevar esto al siguiente nivel, así que configuremos un proyecto simple utilizando Jasmine.


Paso 2: Configuración de un proyecto

El jazmín se puede usar solo; o puedes integrarlo con un proyecto de Rails. Haremos lo primero. Mientras que Jasmine puede ejecutarse fuera del navegador (piense en Node, entre otros lugares), podemos obtener una pequeña plantilla realmente agradable con la descarga.

Entonces, dirígete a la página de descarga independiente y obtén la última versión. Deberías conseguir algo como esto:

Encontrarás los archivos reales del framework Jasmine en el lib carpeta. Si prefiere estructurar sus proyectos de manera diferente, por favor hágalo; Pero vamos a mantener esto por ahora.

En realidad, hay un código de ejemplo conectado en esta plantilla de proyecto. ¿El actual? JavaScript (el código que queremos probar) se puede encontrar en el src subdirectorio; Estaremos poniendo el nuestro en breve. El código de prueba-el especificaciones-entra en el especulación carpeta. No te preocupes por el SpecHelper.js archivo todavía volveremos a eso.

Ese SpecRunner.html archivo es lo que ejecuta las pruebas en un navegador. Ábralo (y marque la casilla de verificación "aprobado" en la esquina superior derecha), y debería ver algo como esto:

Esto nos muestra que todas las pruebas para el proyecto de muestra están pasando. Una vez que haya terminado este tutorial, le recomiendo que abra el spec / PlayerSpec.js archivar y leer ese código. Pero en este momento, vamos a probar estas cosas de escritura de prueba.

  • Crear convert.js en el src carpeta.
  • Crear convertSpec.js en el especulación carpeta,
  • Copia el SpecRunner.html archivar y renombrarlo SpecRunner.original.html.
  • Eliminar los enlaces a los archivos de proyecto de muestra en SpecRunner.html y añade estas lineas:

Ahora estamos listos para crear una mini biblioteca que convertirá entre unidades de medida. Comenzaremos escribiendo las pruebas para nuestra mini-biblioteca..


Paso 3: Escribir las pruebas

Entonces, vamos a escribir nuestras pruebas, vamos?

describe ("Convertir biblioteca", función () describe ("convertidor de distancia", función () ); describe ("convertidor de volumen", función () ););

Comenzamos con esto; estamos probando nuestro Convertir biblioteca. Notarás que estamos anidando describir declaraciones aquí Esto es perfectamente legal. En realidad, es una excelente manera de probar fragmentos de funcionalidad separados del mismo código base. En lugar de dos separados describir llamadas para Convertir conversiones a distancia de la biblioteca y conversiones de volumen, podemos tener un conjunto de pruebas más descriptivo como este.

Ahora, en las pruebas reales. Repetiré el interior describir llama aquí para tu conveniencia.

describe ("convertidor de distancia", función () it ("convierte pulgadas a centímetros", función () espera (Convertir (12, "en") a ("cm")). toEqual (30.48);) ; ("convierte centímetros a yardas", función () esperar (Convertir (2000, "cm"). a ("yardas")). toEqual (21.87);););

Aquí están nuestras pruebas para conversiones a distancia. Es importante notar algo aquí: no hemos escrito una parte del código para nuestros Convertir Aún así, en estas pruebas estamos haciendo más que solo verificar si funciona: en realidad estamos decidiendo cómo se usará (y, por lo tanto, se implementará). Así es como hemos decidido hacer nuestras conversiones:

Convertir(, ).a();

Sí, estoy siguiendo el ejemplo de la forma en que Jasmine ha implementado sus pruebas, pero creo que es un buen formato. Entonces, en estas dos pruebas, yo mismo hice las conversiones (bueno, con una calculadora) para ver cuáles deberían ser los resultados de nuestras llamadas. Estamos usando el A igual Matcher para ver si nuestras pruebas pasan..

Aquí están las pruebas de volumen:

describe ("convertidor de volumen", función () it ("convierte litros a galones", función () espera (Convertir (3, "litros") a ("galones")). toEqual (0.79);) ; ("convierte galones a tazas", función () esperar (Convertir (2, "galones"). a ("tazas")). toEqual (32);););

Y voy a agregar dos pruebas más en nuestro nivel superior. describir llamada:

it ("emite un error cuando se pasa una unidad de origen desconocida", function () var testFn = function () Convert (1, "dollar") to ("yens"); expect (testFn) .toThrow ( nuevo error ("desde la unidad no reconocida"));); it ("emite un error cuando se pasa una unidad desconocida", function () var testFn = function () Convert (1, "cm"). ((furlongs "); expect (testFn) .toThrow ( nuevo error ("unidad no reconocida")););

Estos revisan los errores que deben lanzarse cuando se pasan unidades desconocidas a cualquiera de los dos. Convertir función o la a método. Notarás que estoy envolviendo la conversión real en una función y pasándola a la esperar función. Eso es porque no podemos llamar a la función como la esperar parámetro; Necesitamos darle una función y dejar que llame a la función en sí. Ya que tenemos que pasar un parámetro a ese a Función, podemos hacerlo de esta manera..

La otra cosa a tener en cuenta es que estoy introduciendo un nuevo comparador: tirar, que toma un objeto de error. Veremos algunos más matchers pronto..

Ahora, si abres SpecRunner.html en un navegador, obtendrás esto:

¡Genial! Nuestras pruebas están fallando. Ahora, vamos a abrir nuestro convert.js archivar y hacer algún trabajo:

función Convertir (número, desde Unidad) var conversions = distancia: metros: 1, cm: 0.01, pies: 0.3048, pulgadas: 0.0254, yardas: 0.9144, volumen: litros: 1, galones: 3.785411784, tazas: 0.236588236 , betweenUnit = false, type, unit; para (ingrese conversiones) if (conversiones (type)) if ((unit = conversions [type] [fromUnit])) betweenUnit = number * unit * 1000;  devolver a: function (toUnit) if (betweenUnit) for (escribir conversiones) if (conversions.hasOwnProperty (type)) if ((unit = conversions [type] [toUnit])) return fix (betweenUnit / (unit * 1000));  lanzar un nuevo error ("no reconocido a la unidad");  else lanza un nuevo error ("no reconocido de la unidad");  function fix (num) return parseFloat (num.toFixed (2)); ; 

Realmente no vamos a discutir esto, porque estamos aprendiendo Jasmine aquí. Pero aquí están los puntos principales:

  • Estamos haciendo las conversiones almacenando la conversión en un objeto; Los números de conversión se clasifican por tipo (distancia, volumen, agregue el suyo propio). Para cada campo de medición, tenemos un valor base (metros o litros, aquí) al que todo convierte. Así que cuando veas yardas: 0.9144, sabes que es la cantidad de yardas que hay en un metro. Luego, para convertir yardas a, digamos, centímetros, multiplicamos yardas por el primer parámetro (para obtener el número de metros) y luego dividir el producto por cm, El número de metros en un centímetro. De esta manera, no tenemos que almacenar las tasas de conversión para cada par de valores. Esto también hace que sea fácil agregar nuevos valores más tarde.
  • En nuestro caso, esperamos que las unidades pasadas sean las mismas que las claves que usamos en la tabla de conversión. Si se tratara de una biblioteca real, deberíamos admitir múltiples formatos, como 'in', 'inch' y 'inches', y, por lo tanto, queremos agregar algo de lógica para que coincida con el de la Unidad a la tecla correcta.
  • Al final de Convertir función, almacenamos el valor intermedio en entre unidad, que se inicializa a falso. De esa manera, si no tenemos la de la Unidad, entre unidad estarán falso entrar en el a Método, y así un error con ser lanzado..
  • Si no tenemos el a la unidad, Se lanzará un error diferente. De lo contrario, dividiremos según sea necesario y devolveremos el valor convertido..

Ahora, vuelve a SpecRunner.html y vuelve a cargar la página. Ahora debería ver esto (¿después de verificar? ¿Mostrar aprobado?):

¡Ahí tienes! Nuestras pruebas están pasando. Si estuviésemos desarrollando un proyecto real aquí, escribiríamos pruebas para una cierta parte de la funcionalidad, las haremos pasar, escribiremos pruebas para otra prueba, las haremos, etc. Pero como era un ejemplo simple, lo hemos hecho. todo en un solo golpe.

Y ahora que has visto este sencillo ejemplo de uso de Jasmine, veamos algunas características más que te ofrece..


Paso 4: Aprendiendo los Matchers

Hasta ahora, hemos utilizado dos matchers: A igual y tirar. Hay, por supuesto, muchos otros. Aquí hay algunos que probablemente encuentres útiles; Puedes ver la lista completa en la wiki..

toBeDefined / toBeUndefined

Si solo quiere asegurarse de que una variable o propiedad esté definida, hay un emparejador para eso. También hay uno para confirmar que una variable o propiedad es indefinido.

it ("is defined", function () var name = "Andrew"; expect (name) .toBeDefined ();) it ("no está definido", function () var name; expect (name) .toBeUndefined (););

toBeTruthy / toBeFalsy

Si algo debe ser verdadero o falso, estos emparejadores lo harán..

it ("is true", function () expect (Lib.isAWeekDay ()). toBeTruthy ();); it ("is false", function () expect (Lib.finishedQuiz) .toBeFalsy (););

toBeLessThan / toBeGreaterThan

Por todo lo que numeras personas. Ya sabes cómo funcionan estos:

it ("es menor que 10", función () esperar (5) .toBeLessThan (10);); it ("es mayor que 10", función () expect (20) .toBeGreaterThan (10););

para hacer coincidir

¿Tiene algún texto de salida que debe coincidir con una expresión regular? los para hacer coincidir el matcher esta listo y dispuesto.

it ("genera el texto correcto", function () expect (cart.total ()) .Match (/ \ $ \ d *. \ d \ d /););

contener

Este es bastante útil. Comprueba si una matriz o cadena contiene un elemento o subcadena.

it ("debería contener naranjas", function () expect (["apples", "naranjas", "peras"]). toContain ("naranjas"););

También hay algunos otros emparejadores que puedes encontrar en la wiki. ¿Pero qué pasa si quieres un matcher que no existe? En realidad, debería poder hacer casi cualquier cosa con un código de configuración y los emparejadores que proporciona Jasmine, pero a veces es mejor abstraer algo de esa lógica para tener una prueba más legible. En forma casual (bueno, en realidad no), Jasmine nos permite crear nuestros propios emparejadores. Pero para hacer esto, primero debemos aprender algo más..

Paso 5: Cubriendo antes y después

A menudo, al probar una base de código, querrá realizar algunas líneas de código de configuración para cada prueba de una serie. Sería doloroso y detallado tener que copiar eso para cada eso llame, así que Jasmine tiene una pequeña característica útil que nos permite designar un código para ejecutar antes o después de cada prueba. Veamos cómo funciona esto:

describe ("MyObject", function () var obj = new MyObject (); beforeEach (function () obj.setState ("clean");); it ("cambia de estado", function () obj.setState ("dirty"); expect (obj.getState ()). toEqual ("dirty");) it ("agrega estados", function () obj.addState ("packaged"); expect (obj.getState ( )). toEqual (["clean", "packaged"]);));

En este ejemplo artificial, puede ver cómo, antes de ejecutar cada prueba, el estado de obj está configurado para "limpiar". Si no hicimos esto, el cambio realizado en un objeto en una prueba anterior se mantendrá en la siguiente prueba de forma predeterminada. Por supuesto, también podríamos hacer algo similar con el Después de cada función:

describe ("MyObject", function () var obj = new MyObject ("clean"); // establece el estado inicial afterEach (function () obj.setState ("clean");); it ("cambia el estado" , function () obj.setState ("dirty"); expect (obj.getState ()). toEqual ("dirty");) it ("agrega estados", function () obj.addState ("packaged" ); expect (obj.getState ()). toEqual (["clean", "packaged"]);));

Aquí, para empezar, estamos configurando el objeto y luego lo corregimos. después cada prueba Si quieres el MyObject para que pueda probar este código, puede obtenerlo aquí en una lista de GitHub.

Paso 6: Escribiendo Matchers personalizados

Como dijimos anteriormente, los emparejadores de clientes probablemente serían útiles a veces. Así que vamos a escribir uno. Podemos añadir un matcher en una Antes de cada llamar o un eso llamada (bueno, supongo que tu podría hazlo en una Después de cada llamada, pero eso no tendría mucho sentido). Así es como empiezas:

beforeEach (function () this.addMatchers (););

Bastante simple, ¿eh? Nosotros llamamos this.addMatchers, pasándole un parámetro objeto. Cada clave en este objeto se convertirá en el nombre de un igualador, y la función asociada (el valor) será cómo se ejecuta. Digamos que queremos crear un matcher que compruebe si un número está entre otros dos. Esto es lo que escribirías:

beforeEach (function () this.addMatchers (toBeBetween: function (rangeFloor, rangeCeiling) if (rangeFloor> rangeCeiling) var temp = rangeFloor; rangeFloor = rangeCeiling; rangeCeiling = temp; devolver este> rangeFloor && this. real < rangeCeiling;  ); );

Simplemente tomamos dos parámetros, nos aseguramos de que el primero sea más pequeño que el segundo y devolvamos una declaración booleana que se evalúa como verdadera si se cumplen nuestras condiciones. Lo importante a tener en cuenta aquí es cómo conseguimos una retención del valor que se pasó a la esperar función: esto.actual.

it ("está entre 5 y 30", función () expect (10) .toBeBetween (5, 30);); it ("está entre 30 y 500", función () esperar (100) .toBeBetween (500, 30););

Esto es lo que el SpecHelper.js archivo hace tiene un antes de cada llamada que agrega el matcher tobeJugar (). Echale un vistazo!


Conclusión: divirtiéndose!

Hay mucho más que puede hacer con Jasmine: comparadores relacionados con funciones, espías, especificaciones asíncronas y más. Te recomiendo que explores la wiki si te interesa. También hay algunas bibliotecas que lo acompañan que facilitan las pruebas en el DOM: Jasmine-jQuery y Jasmine-fixture (que depende de Jasmine-jQuery).

Entonces, si no está probando su JavaScript hasta ahora, este es un excelente momento para comenzar. Como hemos visto, la sintaxis rápida y simple de Jasmine hace que las pruebas sean bastante simples. Simplemente no hay razón para que no lo hagas, ahora, ¿está ahí??

Si desea ampliar su desarrollo de JavaScript, ¿por qué no echa un vistazo a la gama de elementos de JavaScript en Envato Market? Hay miles de scripts, aplicaciones y fragmentos de código para ayudarte.