如何从AngularJS控制器测试返回值的承诺茉莉? [英] How to Test Value Returned in Promise from AngularJS Controller with Jasmine?

查看:157
本文介绍了如何从AngularJS控制器测试返回值的承诺茉莉?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个公开,返回休息后,调用一些文本功能的控制器。它工作正常,但我有麻烦茉莉花测试。 承诺处理程序中的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();
  });
});

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();
  });
});

这篇关于如何从AngularJS控制器测试返回值的承诺茉莉?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆