如何从AngularJS控制器测试返回值的承诺茉莉?茉莉、控制器、返回值、测试

2023-09-13 04:01:36 作者:野污

我有一个公开,返回休息后,调用一些文本功能的控制器。它工作正常,但我有麻烦茉莉花测试。 承诺处理程序中的code在测试中从未执行

控制器:

  / *全球Q * /使用严格的;angular.module(MyModule的',['some.service'])    .controller('MyCtrl',['$范围,SomeSvc',函数($范围,SomeSvc){        $ scope.getTheData =功能(ID){            VAR递延= Q.defer();            VAR processedResult ='';            SomeSvc.getData(id)的                。然后(功能(结果){                    //处理数据                    processedResult ='一些东西';                    deferred.resolve(processedResult);                })                .fail(功能(错误){                    deferred.reject(ERR);                });            返回deferred.promise;        }    }]); 

测试:

 描述(有些测试',函数(){    变量$范围;    变量$控制器;    变量$ httpBackend;    beforeEach(函数(){        模块('Mymodule中');        注(功能(_ $ rootScope_,_ $ controller_,_ $ httpBackend_){            。$ SCOPE = _ $ rootScope _ $新();            $控制器= _ $ controller_;            $ httpBackend = _ $ httpBackend_;            //嘲笑调用来自控制器的SomeSvc通话将            $ httpBackend.expect('GET','在/ URL /到/我/数据);            $ httpBackend.whenGET(简称/ URL /到/我/数据)                .respond({数据:大量的数据'});            $控制器('MyCtrl',{                $范围:$范围            });        });    });    描述(测试自许返回值',函数(){        VAR舞会= $ scope.getTheData(someId);        prom.then(功能(结果){            预期(结果).toBe(意料中事); //这个code从不运行        })    });}); 

解决方案

我会做的是使用间谍的成功和失败的回调,并期望成功回调已经调用所需的数据。

中的任何内容,然后将不会被运行,除非承诺回调被称为 - 这是你的风险。 测试将自期望从未运行。传递所以不要使用期望然后在测试中。手摇一切来代替。使用 $ httpBackend.flush() $ timeout.flush()范围。$适用于(),其中需要得到控制器/服务去的一步的。这使你可以看到,国家就是你希望它是变更后/前的东西。

因为你可能想测试阴性结果为好,最好是使用 $ httpBackend.expectGet()。响应() $ httpBackend .flush() whenGet()。这样,您就可以测试被拒绝的值也是一个新的测试是正确的。 刷新将触发消化周期都优秀的请求接收数据。

whenGet / whenPost是最好的一个mockServer模块,这样就可以不用服务器运行应用程序(应该可以提出请求任意次数)。

试试这个退出

 描述('MyCtrl.getData',函数(){  VAR    $范围;    $控制器;    $ httpBackend;  beforeEach(函数(){    模块('Mymodule中');    注(功能(_ $ rootScope_,_ $ controller_,_ $ httpBackend_){        。$ SCOPE = _ $ rootScope _ $新();        $控制器= _ $ controller_;        $ httpBackend = _ $ httpBackend_;        $控制器('MyCtrl',{          $范围:$范围        });    });  它('应通过承诺成功返回的数据',函数(){    VAR      数据= {数据:大量数据},      successSpy = jasmine.createSpy(成功),      failureSpy = jasmine.createSpy(失败);    $ scope.getTheData(someId)。然后(successSpy,failureSpy);    。$ httpBackend.expect('GET','在/ URL /到/我/数据)响应(200,数据);    $ httpBackend.flush();    期待(successSpy).toHaveBeenCalledWith(数据);    期待(failureSpy).not.toHaveBeenCalled();  });  它('应通过承诺如果服务器坏了拒绝数据',函数(){    VAR      successSpy = jasmine.createSpy(成功),      failureSpy = jasmine.createSpy(失败);    $ scope.getTheData(someId)。然后(successSpy,failureSpy);    $ httpBackend.expect('GET','在/ URL /到/我/数据)响应(500)。    $ httpBackend.flush();    期待(successSpy).not.toHaveBeenCalled();    期待(failureSpy).toHaveBeenCalled();  });}); 
实例解说AngularJS在自动化测试中的应用

I have a controller that expose a function that returns some text after a rest call. It works fine, but I'm having trouble testing it with Jasmine. The code inside the promise handler in the test never executes.

The controller:

/* global Q */
'use strict';
angular.module('myModule', ['some.service'])
    .controller('MyCtrl', ['$scope', 'SomeSvc', function ($scope, SomeSvc) {

        $scope.getTheData = function (id) {
            var deferred = Q.defer();
            var processedResult = '';
            SomeSvc.getData(id)
                .then(function (result) {
                    //process data
                    processedResult = 'some stuff';
                    deferred.resolve(processedResult);
                })
                .fail(function (err) {
                    deferred.reject(err);
                });
            return deferred.promise;
        }
    }]);

The test:

describe('some tests', function() {
    var $scope;
    var $controller;
    var $httpBackend;
    beforeEach(function() {
        module('myModule');
        inject(function(_$rootScope_, _$controller_, _$httpBackend_) {
            $scope = _$rootScope_.$new();
            $controller = _$controller_;
            $httpBackend = _$httpBackend_;
            //mock the call that the SomeSvc call from the controller will make
            $httpBackend.expect('GET', 'the/url/to/my/data');
            $httpBackend.whenGET('the/url/to/my/data')
                .respond({data:'lots of data'});
            $controller ('MyCtrl', {
                $scope: $scope
            });
        });
    });

    describe('test the returned value from the promise', function() {
        var prom = $scope.getTheData(someId);
        prom.then(function(result) {
            expect(result).toBe('something expected');  //this code never runs
        })
    });
});

解决方案

What I would do is to use a spy for the success and failure callbacks, and expect the success callback to have been called with the data you expect.

Anything inside a then will not be run unless the promise callbacks are called - which is a risk for you. The test will pass since the expect was never run. So don't use expect inside then in tests. Hand crank everything instead. Use $httpBackend.flush(), $timeout.flush(), scope.$apply() where needed to get the controller/services to go one step further. This let's you see that the state is what you want it to be before/after the change.

Since you might want to test negative results as well, it's better to use $httpBackend.expectGet().respond() and $httpBackend.flush() than whenGet(). This way you can test that the rejected value is also correct in a new test. flush will trigger a digest cycle and have all outstanding requests receive their data.

whenGet/whenPost is best for a mockServer module, so that you can run your application without a server (should be possible to make a request any number of times).

Try this out

describe('MyCtrl.getData', function() {
  var
    $scope;
    $controller;
    $httpBackend;

  beforeEach(function() {
    module('myModule');
    inject(function(_$rootScope_, _$controller_, _$httpBackend_) {
        $scope = _$rootScope_.$new();
        $controller = _$controller_;
        $httpBackend = _$httpBackend_;
        $controller ('MyCtrl', {
          $scope: $scope
        });
    });

  it('should return data successfully through promise', function() {
    var
      data = { data: 'lots of data' },
      successSpy = jasmine.createSpy('success'),
      failureSpy = jasmine.createSpy('failure');

    $scope.getTheData(someId).then(successSpy, failureSpy);

    $httpBackend.expect('GET', 'the/url/to/my/data').respond(200, data);
    $httpBackend.flush();

    expect(successSpy).toHaveBeenCalledWith(data);
    expect(failureSpy).not.toHaveBeenCalled();
  });

  it('should reject data through promise if the server is broken', function() {
    var
      successSpy = jasmine.createSpy('success'),
      failureSpy = jasmine.createSpy('failure');

    $scope.getTheData(someId).then(successSpy, failureSpy);

    $httpBackend.expect('GET', 'the/url/to/my/data').respond(500);
    $httpBackend.flush();

    expect(successSpy).not.toHaveBeenCalled();
    expect(failureSpy).toHaveBeenCalled();
  });
});

 
精彩推荐
图片推荐