Hola, soy Miguel y para hoy les traigo otro post.
Las pruebas unitarias son una de las medidas más valiosas y tediosas de su base de código al mismo tiempo. Escribir pruebas lleva mucho tiempo y podría ser otro tipo de «sub-aplicación» cerca de su código principal.
Si se manejan correctamente, las pruebas unitarias pueden salvarle la vida y la mente al depurar el código. ¡Todos lo sabemos!
Este enfoque lo ayudará a configurar un entorno de pruebas unitarias obstinado con TypeScript que también funciona para proyectos de JavaScript.
Puede crear su próximo proyecto siguiendo este enfoque, o puede adaptar su aplicación existente con un esfuerzo «absolutamente nulo». Este enfoque es tanto para un cliente como para una aplicación de servidor.
Índice
Preparar
Comencemos con la estructura de carpetas del proyecto.
root | node_modules | src | test | package.json | tsconfig.json
Consideré una carpeta de prueba dedicada en la que organizará sus pruebas siguiendo la misma estructura interna de la carpeta src
. No es estrictamente necesario.
También funciona si desea mantener un enfoque común y mantener las pruebas en la carpeta de componentes para los proyectos del lado del cliente. También funcionará.
Como es habitual, para proyectos de JavaScript / TypeScript
, necesitamos algunas dependencias.
npm install --dev ts-node mocha @testdeck/mocha nyc chai ts-mockito
O
yarn add -D ts-node mocha @testdeck/mocha nyc chai ts-mockito
Que obtendremos:
- Ts-nodo: permitir a ejecutar
Ts
archivo portranspiling
sobre la marcha. - Mocha: lo usaremos como corredor de prueba.
- @ testdeck / mocha: permitirá que mocha interprete las clases de
TypeScript
como suites de prueba. - Nyc: generará el informe de cobertura.
- Chai: la biblioteca de expectativas que usaremos.
- Ts-mockito: una biblioteca genial de
stubbing
y burla inspirada enmockito
paraJava
.
Bueno, lo primero que debe hacer es configurar tsconfig.json
. Supongo que tiene un tsconfig
raíz para su proyecto, sea lo que sea. Basado en el principal, puede crear un tsconfig.json
para pruebas dentro de la carpeta de prueba.
| node_modules | src | test | --- tsconfig.json | package.json | tsconfig.json
{ "extends": "../tsconfig.json", "compilerOptions": { "baseUrl": "./", "module": "commonjs", "experimentalDecorators": true, "strictPropertyInitialization": false, "isolatedModules": false, "strict": false, "noImplicitAny": false, "typeRoots" : [ "../node_modules/@types" ] }, "exclude": [ "../node_modules" ], "include": [ "./**/*.ts" ] }
Si está familiarizado con TypeScript
, la configuración anterior no es nada especial. Las principales cosas importantes para preservar son módulo y el decoradores experimentales propiedades. Aparte de eso, puede cambiarlo cuando lo necesite.
Luego, necesitamos configurar un archivo en la carpeta raíz que permita ts-nodo
para ejecutar y transpilar las pruebas:
| node_modules | src | test | --- tsconfig.json | package.json | register.js | tsconfig.json
/** * Overrides the tsconfig used for the app. * In the test environment we need some tweaks. */ const tsNode = require('ts-node'); const testTSConfig = require('./tests/tsconfig.json'); tsNode.register({ files: true, transpileOnly: true, project: './tests/tsconfig.json' });
El archivo de registro carga el tsconfig
para instrumentar el ts-nodo
. Mejora el rendimiento con un compromiso insignificante.
transpileOnly
le dice a TypeScript
que evite verificar el código de prueba durante la fase de «compilación». En general, no es arriesgado, solo prueba el código y no el de producción.El resultado es que detectará los errores de transpilación cuando se ejecuten las pruebas en lugar de en el momento de la compilación.
De todos modos, este pequeño truco permite especificar las propiedades solo para el ts-nodo
, por lo que su IDE
seguirá usando el original tsconfig
para comprobar los archivos de prueba durante la escritura del código. No está mal.
Los dos últimos archivos que debemos agregar al proyecto son:
| node_modules | src | test | --- tsconfig.json | .mocharc.json | .nyrc.json | package.json | register.js | tsconfig.json
{ "require": "./register.js", "reporter": "dot" }
{ "extends": "@istanbuljs/nyc-config-typescript", "include": [ "src/**/*.ts" ], "exclude": [ "node_modules/" ], "extension": [ ".ts" ], "reporter": [ "text-summary", "html" ], "report-dir": "./coverage" }
Bien hecho. Estos dos archivos permiten a mocha
estar al tanto del register.js
que acabamos de crear y Nueva York para generar la cobertura HTML
dentro de la carpeta ./coverage
. Intente experimentar con las opciones para producir resultados diferentes.
Estamos en el último paso de configuración. Queremos realizar las pruebas. Entonces, abra su package.json
y agregue la siguiente entrada en el objeto de scripts:
"test": "nyc ./node_modules/.bin/_mocha 'tests/**/*.ts'",
Como práctica recomendada, suelo añadir un sufijo a mis archivos de prueba. Esto me permite distinguir los archivos con los que quiero ejecutar con mocha
de las utilidades que podría crear durante el ciclo de vida del proyecto. Dado eso, el comando anterior sería:
"test": "nyc ./node_modules/.bin/_mocha 'tests/**/*.test.ts'",
Pruebas
Ahora que tenemos el entorno de prueba completo configurado, debemos comenzar a probar el código.
Creemos nuestra prueba de hola mundo.
import { suite, test } from '@testdeck/mocha'; import * as _chai from 'chai'; import { mock, instance } from 'ts-mockito'; import { HelloWorldService } from '../src/logger/hello-world.service.ts'; import { Logger } from '../src/logger/logger.ts';_chai.should(); @suite class HelloWorldServiceUnitTests { private SUT: HelloWorldService; private loggerMock: Logger; before() { this.loggerMock = mock(Logger); this.SUT = new HelloWorldService(instance(this.loggerMock)); } @test 'should do something when call a method'() { this.SUT.should.be.not.undefined; } }
Es la estructura genérica de una prueba. Puede usar clases de TypeScript
con suite
decorador para marcar las clases como una suite y prueba decorador para hacer que los métodos se puedan ejecutar en pruebas.
Como puede ver, definí los métodos como cadenas. Mejora la legibilidad, pero si lo prefiere, puede utilizar métodos tradicionales.
Dado el script que acabamos de configurar, puede ejecutar la prueba con:
npm test
O
yarn test
Para configurar chai
, importa los decoradores y, haciendo otra pequeña configuración de código, tienes que copiar y pegar algunas líneas de una prueba a otra. Evitarlo podría lograrse utilizando las rutas de TypeScript.
Creemos una nueva carpeta utilidad dentro de la carpeta prueba:
| node_modules | src | test | --- utility | --- tsconfig.json | .mocharc.json | .nyrc.json | package.json | register.js | tsconfig.json
Luego, agreguemos un index.ts
dentro de él con este código:
export { suite, test, params, skip, only } from '@testdeck/mocha'; import * as _chai from 'chai'; const _should = _chai.should(); export const should = _should;
Ahora, edite el tsconfig.json
dentro de prueba carpeta para agregar la sección paths
:
"paths": { "@my-org/my-project/test": [ "./utility/index.ts" ] }
Para que funcione con ts-node
, necesitamos un nuevo paquete:
yarn add -D tsconfig-paths
Además, edite el register.js
y cambia el código con esto:
const tsNode = require('ts-node'); const tsConfigPaths = require('tsconfig-paths'); const mainTSConfig = require('./tsconfig.json'); const testTSConfig = require('./tests/tsconfig.json'); tsConfigPaths.register({ baseUrl: './test', paths: { ...mainTSConfig.compilerOptions.paths, ...testTSConfig.compilerOptions.paths } }); tsNode.register({ files: true, transpileOnly: true, project: './test/tsconfig.json' });
Frio. Entonces, ahora puede cambiar su declaración de importación en las pruebas:
import { suite, test, should } from '@my-org/my-project/test'; import { mock, instance } from 'ts-mockito'; import { HelloWorldService } from '../src/logger/hello-world.service.ts'; import { Logger } from '../src/logger/logger.ts';_chai.should(); @suite class HelloWorldServiceUnitTests { private SUT: HelloWorldService; private loggerMock: Logger; before() { this.loggerMock = mock(Logger); this.SUT = new HelloWorldService(instance(this.loggerMock)); } @test 'should do something when call a method'() { this.SUT.should.be.not.undefined; } }
Finalmente, puede usar una sola importación para obtener todas las bibliotecas de utilidades a la vez.
Por lo general, configuro mi IDE (PhpStorm) para ejecutar las pruebas usando el pequeño ícono de reproducción que se muestra cerca de la definición del método. Cuando escribo las pruebas, es útil ya que también me permite depurar el código.
Configurar * Strom IDE para ejecutar las pruebas con esta configuración es fácil. Debe ir a Editar configuración y expandir las Plantillas a la izquierda. Simplemente seleccione la plantilla Mocha y elija una configuración como esta:
Ahora, cuando ejecute las pruebas utilizando el icono de reproducción cerca del método de prueba, utilizará esta plantilla para crear la configuración de ejecución para ese método sobre la marcha.
Espero que te sea de utilidad. Gracias por leer este post.
Añadir comentario