Una introducción a las pruebas unitarias en aplicaciones AngularJS

 

 

 

  • ¡Registro!
  • Implemente rápidamente. Implementar inteligentemente

  • Índice
    1. Unas palabras sobre las pruebas unitarias
      1. Qué y qué no probar
    2. Arrancando un entorno de prueba para AngularJS
      1. Karma: El espectacular corredor de pruebas
      2. Moca
      3. chai
      4. Sinón
    3. Pruebas unitarias a nivel de aplicación
    4. Pruebas unitarias a nivel de módulo
      1. Filtros, servicios y fábricas: una historia de inyección de dependencia
      2. Controladores
      3. Directivas
      4. Proveedores
      5. Solicitudes HTTP
    5. Módulo ngMock
      1. $timeout, $log y los demás

    Una de las razones del éxito de AngularJS es su destacada capacidad para ser probado. El factor principal que hizo que Sébastien cambiara de "Bueno, simplemente inicio la aplicación y veo si todo funciona" a "¡Tengo pruebas unitarias!". fue que, por primera vez, pudo concentrarse en lo que importa y en lo que disfruta en la programación: crear algoritmos inteligentes y agradables interfaces de usuario. Después de solucionarlo, volver a actualizar la aplicación y pedir disculpas al servicio de atención al cliente, decidió reescribir por completo este componente en un estilo de desarrollo basado en pruebas. El archivo de prueba terminó siendo el doble de largo que el archivo componente. Se ha mejorado mucho desde entonces, especialmente su pobre rendimiento, pero nunca volvió a fallar en producción. Código sólido como una roca.

     

    AngularJS ha crecido hasta convertirse en uno de los marcos de aplicaciones de una sola página más populares. Desarrollado por un equipo dedicado de Google, el resultado es sustancial y ampliamente utilizado tanto en proyectos comunitarios como industriales.

    Una de las razones del éxito de AngularJS es su destacada capacidad para ser probado. Está fuertemente respaldado por Karma (el espectacular ejecutor de pruebas escrito por Vojta Jína) y sus múltiples complementos. Karma, combinado con sus compañeros Mocha, Chai y Sinon , ofrece un conjunto completo de herramientas para producir código de calidad que sea fácil de mantener, libre de errores y bien documentado.

    “Bueno, simplemente iniciaré la aplicación y veré si todo funciona. Nunca hemos tenido ningún problema para hacer eso”. - Nadie nunca

    El factor principal que me hizo cambiar de "Bueno, simplemente inicio la aplicación y veo si todo funciona" a "¡Tengo pruebas unitarias!". fue que, por primera vez, pude concentrarme en lo que importa y en lo que disfruto en la programación: crear algoritmos inteligentes y agradables interfaces de usuario.

    Recuerdo un componente que se suponía que administraría el menú contextual en una aplicación. Créame, fue un componente complejo. Dependiendo de decenas de condiciones mixtas, podía mostrar u ocultar botones, submenús, etc. Un día actualizamos la aplicación en producción. Puedo recordar cómo me sentí cuando inicié la aplicación, abrí algo, hice clic derecho y no vi ningún menú contextual, solo un feo cuadro vacío que era la prueba definitiva de que algo había salido realmente mal. Después de solucionarlo, volver a actualizar la aplicación y pedir disculpas al servicio de atención al cliente, decidí reescribir por completo este componente en un estilo de desarrollo basado en pruebas. El archivo de prueba terminó siendo el doble de largo que el archivo componente. Se ha mejorado mucho desde entonces, especialmente su pobre rendimiento, pero nunca volvió a fallar en producción. Código sólido como una roca.

    Unas palabras sobre las pruebas unitarias

    Las pruebas unitarias se han convertido en un estándar en la mayoría de las empresas de software. Las expectativas de los clientes han alcanzado un nuevo máximo y ya nadie acepta recibir dos regresiones gratuitas por el precio de una actualización.

    Si está familiarizado con las pruebas unitarias, entonces ya sabrá qué tan seguro se siente un desarrollador al refactorizar el código probado. Si no está familiarizado, imagínese deshacerse del estrés de la implementación, un estilo de codificación de "codificar y rezar" y un desarrollo interminable de funciones. ¿La mayor parte de? Es automático.

     

    Las pruebas unitarias mejoran la ortogonalidad del código . Básicamente, el código se denomina "ortogonal" cuando es fácil de cambiar. Corregir un error o agregar una característica no implica más que cambiar el comportamiento del código, como se explica en The Pragmatic Programmer: From Journeyman to Master . Las pruebas unitarias mejoran enormemente la ortogonalidad del código al obligarte a escribir unidades lógicas modulares, en lugar de grandes fragmentos de código.

    Las pruebas unitarias también le proporcionan documentación que siempre está actualizada y que le informa sobre las intenciones y el comportamiento funcional del código. Incluso si un método tiene un nombre críptico (lo cual es malo, pero no entraremos en eso aquí), sabrás instantáneamente lo que hace al leer su prueba.

    Las pruebas unitarias tienen otra gran ventaja. Te obliga a usar tu código y detectar fallas de diseño y malos olores. Toma funciones. ¿Qué mejor manera de asegurarse de que las funciones estén desacopladas del resto de su código que poder probarlas sin ningún código repetitivo?

    Además, las pruebas unitarias abren la puerta al desarrollo basado en pruebas . Si bien no es el tema de este artículo, no puedo enfatizar lo suficiente que el desarrollo basado en pruebas es una forma maravillosa y productiva de escribir código.

    Qué y qué no probar

    Las pruebas deben definir la API del código. Este es el único principio que nos guiará a lo largo de este viaje. Una aplicación AngularJS está, por definición, compuesta de módulos. Los ladrillos elementales se materializan por diferentes conceptos relacionados con la granularidad con que se los mira. A nivel de aplicación, estos ladrillos son módulos de AngularJS. A nivel de módulo son directivas, controladores, servicios, filtros y fábricas. Cada uno de ellos es capaz de comunicarse con otro a través de su interfaz externa.

    Todos estos ladrillos comparten un atributo común. Se comportan como cajas negras, lo que significa que tienen un comportamiento interno y una interfaz externa materializada por entradas y salidas. Para eso precisamente están las pruebas unitarias: para probar las interfaces exteriores de los ladrillos.

    Ignorar los aspectos internos tanto como sea posible se considera una buena práctica. Las pruebas unitarias, y las pruebas en general, son una combinación de estímulos y reacciones.

    Arrancando un entorno de prueba para AngularJS

    Para configurar un entorno de prueba decente para su aplicación AngularJS, necesitará varios módulos npm. Echemos un vistazo rápido a ellos.

    Karma: El espectacular corredor de pruebas

    Karma es un motor que ejecuta pruebas de código. Aunque ha sido escrito para AngularJS, no está específicamente vinculado a él y puede usarse para cualquier aplicación JavaScript. Es altamente configurable a través de un archivo JSON y el uso de varios complementos.

    Todos los ejemplos de este artículo se pueden encontrar en el proyecto dedicado de GitHub , junto con el siguiente archivo de configuración para Karma.

    // Karma configuration// Generated on Mon Jul 21 2014 11:48:34 GMT+0200 (CEST)module.exports = function(config) { config.set({ // base path used to resolve all patterns (e.g. files, exclude) basePath: ’, // frameworks to use frameworks: ['mocha', 'sinon-chai'], // list of files / patterns to load in the browser files: [ 'bower_components/angular/angular.js', 'bower_components/angular-mocks/angular-mocks.js', 'src/*.js', 'test/*.mocha.js' ], // list of files to exclude exclude: [], // preprocess matching files before serving them to the browser preprocessors: { 'src/*.js': ['coverage'] }, coverageReporter: { type: 'text-summary', dir: 'coverage/' }, // test results reporter to use reporters: ['progress', 'coverage'], // web server port port: 9876, // enable / disable colors in the output (reporters and logs) colors: true, // level of logging logLevel: config.LOG_INFO, // enable / disable watching file and executing tests on file changes autoWatch: true, // start these browsers browsers: ['PhantomJS'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: false });};

    Este archivo se puede generar automáticamente escribiendo karma initen una ventana de terminal. Las claves disponibles se describen en la documentación de Karma .

     

    Observe cómo se declaran las fuentes y los archivos de prueba. También hay un recién llegado: ngMock (es decir angular-mocks.js). ngMock es un módulo de AngularJS que proporciona varias utilidades de prueba (más información al final de este artículo).

    Moca

    Mocha es un marco de prueba para JavaScript. Maneja conjuntos de pruebas y casos de prueba, y ofrece buenas funciones de generación de informes. Utiliza una sintaxis declarativa para anidar expectativas en casos y suites. Veamos el siguiente ejemplo (robado descaradamente de la página de inicio de Mocha):

    describe('Array', function() { describe('#indexOf()', function() { it('should return -1 when the value is not present', function() { assert.equal(-1, [1,2,3].indexOf(5)); assert.equal(-1, [1,2,3].indexOf(0)); }); });});

    Puede ver que toda la prueba está contenida en una describellamada. Lo interesante de anidar llamadas a funciones de esta manera es que las pruebas siguen la estructura del código . Aquí, la Arraysuite se compone de una sola subsuite, #indexOf. Se podrían añadir otros, por supuesto. Este subconjunto se compone de un caso, que a su vez contiene dos afirmaciones y expectativas. Es esencial organizar los conjuntos de pruebas en un todo coherente. Garantiza que los errores de prueba se informarán con mensajes significativos, lo que facilita el proceso de depuración.

    chai

    Hemos visto cómo Mocha proporciona capacidades de conjuntos de pruebas y casos de pruebas para JavaScript. Chai , por su parte, ofrece varias formas de comprobar cosas en casos de prueba. Estas comprobaciones se realizan mediante lo que se denominan "afirmaciones" y básicamente marcan un caso de prueba como fallido o aprobado. La documentación de Chai tiene más información sobre los diferentes estilos de afirmaciones.

    Sinón

    Sinon se describe a sí mismo como "espías de prueba, resguardos y simulacros independientes para JavaScript". Los espías, los talones y los simulacros responden a la misma pregunta: ¿Cómo se reemplaza eficientemente una cosa por otra al ejecutar una prueba? Supongamos que tiene una función que toma otra en un parámetro y la llama. Sinon proporciona una forma inteligente y concisa de monitorear si se llama a la función y mucho más (con qué argumentos, cuántas veces, etc.).

     

    Pruebas unitarias a nivel de aplicación

    El objetivo de la interfaz externa de un módulo en una aplicación AngularJS es su capacidad para inyectarse en otro módulo: que exista y tenga una definición válida.

    beforeEach(module('myAwesomeModule'));

    Esto es suficiente y generará un error si myAwesomeModuleno se encuentra por ningún lado.

    Pruebas unitarias a nivel de módulo

    Un módulo AngularJS puede declarar varios tipos de objetos. Algunos son servicios, mientras que otros son más especializados. Repasaremos cada uno de ellos para ver cómo se pueden iniciar en un entorno controlado y luego probarlos.

    Filtros, servicios y fábricas: una historia de inyección de dependencia

    Los filtros, servicios y fábricas (nos referiremos a ellos como servicios en general) se pueden comparar con objetos estáticos o singletons en un marco tradicional orientado a objetos. Son fáciles de probar porque necesitan muy pocas cosas para estar listas y estas cosas suelen ser otros servicios.

    AngularJS vincula servicios a otros servicios u objetos utilizando un modelo de inyección de dependencias muy expresivo, que básicamente significa pedir algo en los argumentos de un método.

    Lo bueno de la forma en que AngularJS inyecta dependencias es que burlarse de las dependencias de un fragmento de código e inyectar cosas en casos de prueba es muy fácil. De hecho, ni siquiera estoy seguro de que pueda ser más sencillo. Consideremos esta fábrica bastante útil:

    angular.module('factories', []).factory('chimp', ['$log', function($log) { return { ook: function() { $log.warn('Ook.'); } };}]);

    ¿Ves cómo $logse inyecta, en lugar del estándar console.warn? Si bien AngularJS no imprimirá $logdeclaraciones en la consola de Karma, evite los efectos secundarios en las pruebas unitarias tanto como sea posible. Una vez reduje a la mitad la duración de las pruebas unitarias de una aplicación burlándome de las solicitudes HTTP de seguimiento, que obviamente fallaban silenciosamente en un entorno local.

    describe('factories', function() { beforeEach(module('factories')); var chimp; var $log; beforeEach(inject(function(_chimp_, _$log_) { chimp = _chimp_; $log = _$log_; sinon.stub($log, 'warn', function() {}); })); describe('when invoked', function() { beforeEach(function() { chimp.ook(); }); it('should say Ook', function() { expect($log.warn.callCount).to.equal(1); expect($log.warn.args[0][0]).to.equal('Ook.'); }); });});

    El patrón para probar filtros, servicios u otros inyectables es el mismo. Sin embargo, los controladores pueden ser un poco más complicados de probar, como veremos ahora. Autoclave de vapor Blog

    Controladores

    Probar un controlador podría generar cierta confusión. ¿Qué probamos? Centrémonos en lo que se supone que debe hacer un controlador. A estas alturas ya debería estar acostumbrado a considerar cualquier elemento probado como una caja negra. Recuerde que AngularJS es un marco de modelo-vista-lo que sea (MVW), lo cual es un poco irónico porque una de las pocas formas de definir algo en una aplicación AngularJS es usar la palabra clave controller. Aun así, cualquier tipo de controlador decente suele actuar como proxy entre el modelo y la vista, a través de objetos en un sentido y devoluciones de llamada en el otro.

     

    El controlador generalmente configura la vista usando algunos objetos de estado, como los siguientes (para una aplicación hipotética de edición de texto):

    angular.module('textEditor', []).controller('EditionCtrl', ['$scope', function($scope) { $scope.state = {toolbarVisible: true, documentSaved: true}; $scope.document = {text: 'Some text'}; $scope.$watch('document.text', function(value) { $scope.state.documentSaved = false; }, true); $scope.saveDocument = function() { $scope.sendHTTP($scope.document.text); $scope.state.documentSaved = true; }; $scope.sendHTTP = function(content) { // payload creation, HTTP request, etc. };}]);

    Lo más probable es que el estado sea modificado tanto por la vista como por el controlador. El toolbarVisibleatributo se alternará mediante, por ejemplo, un botón y un atajo de teclado. Se supone que las pruebas unitarias no prueban las interacciones entre la vista y el resto del universo; para eso están las pruebas de un extremo a otro.

    Sin embargo, el documentSavedvalor será manejado principalmente por el controlador. Probémoslo.

    describe('saving a document', function() { var scope; var ctrl; beforeEach(module('textEditor')); beforeEach(inject(function($rootScope, $controller) { scope = $rootScope.$new(); ctrl = $controller('EditionCtrl', {$scope: scope}); })); it('should have an initial documentSaved state', function(){ expect(scope.state.documentSaved).to.equal(true); }); describe('documentSaved property', function() { beforeEach(function() { // We don't want extra HTTP requests to be sent // and that's not what we're testing here. sinon.stub(scope, 'sendHTTP', function() {}); // A call to $apply() must be performed, otherwise the // scope's watchers won't be run through. scope.$apply(function () { scope.document.text += ' And some more text'; }); }); it('should watch for document.text changes', function() { expect(scope.state.documentSaved).to.equal(false); }); describe('when calling the saveDocument function', function() { beforeEach(function() { scope.saveDocument(); }); it('should be set to true again', function() { expect(scope.state.documentSaved).to.equal(true); }); afterEach(function() { expect(scope.sendHTTP.callCount).to.equal(1); expect(scope.sendHTTP.args[0][0]).to.equal(scope.document.text); }); }); });});

    Un efecto secundario interesante de este fragmento de código es que no solo prueba los cambios en la documentSavedpropiedad, sino que también verifica que el sendHTTPmétodo realmente se llame y con los argumentos adecuados (más adelante veremos cómo probar las solicitudes HTTP). Es por eso que es un método separado publicado en el alcance del controlador. Desacoplar y evitar estados pseudoglobales (es decir, pasar el texto al método, en lugar de dejar que lea el texto en el alcance) siempre facilita el proceso de redacción de pruebas.

     

    Directivas

    Una directiva es la forma que tiene AngularJS de enseñar nuevos trucos a HTML y de encapsular la lógica detrás de esos trucos. Esta encapsulación tiene varios puntos de contacto con el exterior que se definen en el scopeatributo del objeto devuelto. La principal diferencia con la prueba unitaria de un controlador es que las directivas generalmente tienen un alcance aislado, pero ambas actúan como una caja negra y, por lo tanto, se probarán aproximadamente de la misma manera. Sin embargo, la configuración de la prueba es un poco diferente.

    Imaginemos una directiva que muestra un divcon una cadena dentro y un botón al lado. Podría implementarse de la siguiente manera:

    angular.module('myDirectives', []).directive('superButton', function() { return { scope: {label: '=', callback: 'onClick'}, replace: true, restrict: 'E', link: function(scope, element, attrs) { }, template: 'div' + 'div{{label}}/div' + 'button ng-click="callback()"Click me!/button' + '/div' };});

    Queremos probar dos cosas aquí. Lo primero que hay que probar es que la etiqueta se pase correctamente al divcontenido del primero y lo segundo es que algo suceda cuando se haga clic en el botón. Vale la pena decir que la representación real de la directiva pertenece un poco más a las pruebas funcionales y de extremo a extremo, pero queremos incluirla tanto como sea posible en nuestras pruebas unitarias simplemente para fallar rápidamente. Además, trabajar con desarrollo basado en pruebas es más fácil con pruebas unitarias que con pruebas de nivel superior, como pruebas funcionales, de integración y de extremo a extremo.

    describe('directives', function() { beforeEach(module('myDirectives')); var element; var outerScope; var innerScope; beforeEach(inject(function($rootScope, $compile) { element = angular.element('super-button label="myLabel" on-click="myCallback()"/super-button'); outerScope = $rootScope; $compile(element)(outerScope); innerScope = element.isolateScope(); outerScope.$digest(); })); describe('label', function() { beforeEach(function() { outerScope.$apply(function() { outerScope.myLabel = "Hello world."; }); }) it('should be rendered', function() { expect(element[0].children[0].innerHTML).to.equal('Hello world.'); }); }); describe('click callback', function() { var mySpy; beforeEach(function() { mySpy = sinon.spy(); outerScope.$apply(function() { outerScope.myCallback = mySpy; }); }); describe('when the directive is clicked', function() { beforeEach(function() { var event = document.createEvent("MouseEvent"); event.initMouseEvent("click", true, true); element[0].children[1].dispatchEvent(event); }); it('should be called', function() { expect(mySpy.callCount).to.equal(1); }); }); });});

    Este ejemplo tiene algo importante. Vimos que las pruebas unitarias hacen que la refactorización sea muy fácil, pero no vimos exactamente cómo. Aquí, estamos probando que cuando se hace clic en el botón, on-clickse llama a la función pasada como atributo. Si observamos más de cerca el código de la directiva, veremos que esta función cambia de nombre localmente a callback. Se publica con este nombre en el ámbito de aplicación aislado de la directiva. Entonces podríamos escribir la siguiente prueba:

     

    describe('click callback', function() { var mySpy; beforeEach(function() { mySpy = sinon.spy(); innerScope.callback = mySpy; }); describe('when the directive is clicked', function() { beforeEach(function() { var event = document.createEvent("MouseEvent"); event.initMouseEvent("click", true, true); element[0].children[1].dispatchEvent(event); }); it('should be called', function() { expect(mySpy.callCount).to.equal(1); }); });});

    Y también funcionaría. Pero entonces no pondríamos a prueba el aspecto externo de nuestra directiva. Si nos olvidáramos de añadir la clave adecuada a la scopedefinición de la directiva, ninguna prueba nos detendría. Además, en realidad no nos importa si la directiva cambia el nombre de la devolución de llamada o la llama a través de otro método (y si lo hacemos, de todos modos tendrá que probarse en otro lugar).

    Proveedores

    Este es el más difícil de nuestra pequeña serie. ¿Qué es un proveedor exactamente? Es la forma propia de AngularJS de conectar las cosas antes de que se inicie la aplicación. Un proveedor también tiene una faceta de fábrica; de hecho, probablemente conozcas a él $routeProvidery a su hermano pequeño, la $routefábrica. ¡Escribamos nuestro propio proveedor y su fábrica y luego probémoslos!

    angular.module('myProviders', []).provider('coffeeMaker', function() { var useFrenchPress = false; this.useFrenchPress = function(value) { if (value !== undefined) { useFrenchPress = !!value; } return useFrenchPress; }; this.$get = function () { return { brew: function() { return useFrenchPress ? 'Le café.': 'A coffee.'; } }; };});

    No hay nada sofisticado en este proveedor súper útil, que define una bandera y su método de acceso. Podemos ver la parte de configuración y la parte de fábrica (que devuelve el $getmétodo). No repasaré toda la implementación y los casos de uso del proveedor, pero le recomiendo que consulte la documentación oficial de AngularJS sobre proveedores .

    Para probar este proveedor, podríamos probar la parte de configuración por un lado y la parte de fábrica por otro. Sin embargo, esto no sería representativo de la forma en que se utiliza generalmente un proveedor. Pensemos en la forma en que utilizamos los proveedores. Primero, hacemos alguna configuración; luego, utilizamos la fábrica del proveedor en algunos otros objetos o servicios. Podemos ver en nuestro coffeeMakerque su comportamiento depende de la useFrenchPressbandera. Así procederemos. Primero, configuraremos este indicador y luego jugaremos con la fábrica para ver si se comporta en consecuencia.

    describe('coffee maker provider', function() { var coffeeProvider = undefined; beforeEach(function() { // Here we create a fake module just to intercept and store the provider // when it's injected, i.e. during the config phase. angular.module('dummyModule', function() {}) .config(['coffeeMakerProvider', function(coffeeMakerProvider) { coffeeProvider = coffeeMakerProvider; }]); module('myProviders', 'dummyModule'); // This actually triggers the injection into dummyModule inject(function(){}); }); describe('with french press', function() { beforeEach(function() { coffeeProvider.useFrenchPress(true); }); it('should remember the value', function() { expect(coffeeProvider.useFrenchPress()).to.equal(true); }); it('should make some coffee', inject(function(coffeeMaker) { expect(coffeeMaker.brew()).to.equal('Le café.'); })); }); describe('without french press', function() { beforeEach(function() { coffeeProvider.useFrenchPress(false); }); it('should remember the value', function() { expect(coffeeProvider.useFrenchPress()).to.equal(false); }); it('should make some coffee', inject(function(coffeeMaker) { expect(coffeeMaker.brew()).to.equal('A coffee.'); })); });});

    Solicitudes HTTP

    Las solicitudes HTTP no están exactamente al mismo nivel que los proveedores o controladores. Sin embargo, siguen siendo una parte esencial de las pruebas unitarias. Si no tiene una sola solicitud HTTP en toda su aplicación, puede omitir esta sección, afortunado.

     

    En términos generales, las solicitudes HTTP actúan como entradas y salidas en cualquier nivel de su aplicación. En un sistema diseñado completamente con REST, GETlas solicitudes brindan datos a la aplicación y PUTlos POSTmétodos DELETEtoman algunos. Eso es lo que queremos probar y, afortunadamente, AngularJS lo hace fácil.

    Tomemos nuestro ejemplo de fábrica y agreguemosle una POSTsolicitud:

    angular.module('factories_2', []).factory('chimp', ['$http', function($http) { return { sendMessage: function() { $http.post('https://chimps.org/messages', {message: 'Ook.'}); } };}]);

    Obviamente no queremos probar esto en el servidor real, ni queremos parchear el constructor XMLHttpRequest. Ahí es donde $httpBackendentra el juego.

    describe('http', function() { beforeEach(module('factories_2')); var chimp; var $httpBackend; beforeEach(inject(function(_chimp_, _$httpBackend_) { chimp = _chimp_; $httpBackend = _$httpBackend_; })); describe('when sending a message', function() { beforeEach(function() { $httpBackend.expectPOST('https://chimps.org/messages', {message: 'Ook.'}) .respond(200, {message: 'Ook.', id: 0}); chimp.sendMessage(); $httpBackend.flush(); }); it('should send an HTTP POST request', function() { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); });});

    Puede ver que hemos definido qué llamadas se deben realizar al servidor falso y cómo responderlas antes de hacer cualquier otra cosa. Esto es útil y nos permite probar la respuesta de nuestra aplicación a diferentes solicitudes (por ejemplo, ¿cómo se comporta la aplicación cuando la solicitud de inicio de sesión devuelve un 404?). Este ejemplo particular simula una POSTrespuesta estándar.

    Las otras dos líneas del beforeEachbloque son la llamada a la función y un recién llegado $httpBackend.flush(). El servidor falso no responde inmediatamente a cada solicitud; en cambio, le permite verificar cualquier estado intermedio que haya configurado. Espera a que usted le indique explícitamente que responda a cualquier solicitud pendiente que haya recibido.

    La prueba en sí tiene dos métodos de llamada al servidor falso ( verifyNoOutstandingExpectationy verifyNoOutstandingRequest). AngularJS $httpBackendno impone una igualdad estricta entre lo que espera y lo que realmente recibe a menos que usted se lo indique. Puede considerar estas líneas como dos expectativas, una del número de solicitudes pendientes y la otra del número de expectativas pendientes.

    Módulo ngMock

    El módulo ngMock contiene varias utilidades para ayudarlo a suavizar las especificaciones de JavaScript y AngularJS.

    $timeout, $log y los demás

    Usar las dependencias inyectables de AngularJS es mejor que acceder a objetos globales como consoleo window. Consideremos consolelas llamadas. Son resultados similares a las solicitudes HTTP y, de hecho, pueden ser importantes si está implementando una API para la cual se deben registrar algunos errores. Para probarlos, puedes parchear un objeto global, ¡ay! - o utilice el bonito inyectable de AngularJS.

    La $timeoutdependencia también proporciona un flush()método muy conveniente, al igual que $httpBackend. Si creamos una fábrica que proporciona una forma de establecer brevemente un indicador truey luego restaurarlo a su valor original, entonces la forma correcta de probarlo es usar $timeout.

    angular.module('timeouts', []).factory('waiter', ['$timeout', function($timeout) { return { brieflySetSomethingToTrue: function(target, property) { var oldValue = target[property]; target[property] = true; $timeout(function() { target[property] = oldValue; }, 100); } };}]);

    Y la prueba se verá así:

    describe('timeouts', function() { beforeEach(module('timeouts')); var waiter; var $timeout; beforeEach(inject(function(_waiter_, _$timeout_) { waiter = _waiter_; $timeout = _$timeout_; })); descri 




    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Una introducción a las pruebas unitarias en aplicaciones AngularJS

    Una introducción a las pruebas unitarias en aplicaciones AngularJS

    ¡Registro! Implemente rápidamente. Implementar inteligentemente Índice Unas palabras sobre las pruebas

    programar

    es

    https://aprendeprogramando.es/static/images/programar-una-introduccion-a-las-pruebas-unitarias-en-aplicaciones-angularjs-871-0.jpg

    2024-05-20

     

    Una introducción a las pruebas unitarias en aplicaciones AngularJS
    Una introducción a las pruebas unitarias en aplicaciones AngularJS

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20