Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript httpBackend模拟AJAX ES6承诺,单位为$q_Javascript_Angularjs_Ajax_Unit Testing_Jasmine - Fatal编程技术网

Javascript httpBackend模拟AJAX ES6承诺,单位为$q

Javascript httpBackend模拟AJAX ES6承诺,单位为$q,javascript,angularjs,ajax,unit-testing,jasmine,Javascript,Angularjs,Ajax,Unit Testing,Jasmine,我试图模拟对JSONP GET请求的响应,该请求是由一个返回ES6承诺的函数发出的,我在$q.when()中包装了该承诺。代码本身工作得很好,但是,在单元测试中,$httpBackend并没有捕获请求,而是直接到达实际的URL。因此,当调用flush()时,我会收到一个错误,说明错误:没有挂起的刷新请求。JSONP请求是通过ES6承诺中jQuery的$.getJSON()发出的,因此我选择通过提供正则表达式而不是硬编码URL来捕获所有传出请求 我已经搜索了一段时间,试图找出这一点,但仍然没有理解

我试图模拟对JSONP GET请求的响应,该请求是由一个返回ES6承诺的函数发出的,我在
$q.when()
中包装了该承诺。代码本身工作得很好,但是,在单元测试中,$httpBackend并没有捕获请求,而是直接到达实际的URL。因此,当调用
flush()
时,我会收到一个错误,说明
错误:没有挂起的刷新请求。JSONP请求是通过ES6承诺中jQuery的
$.getJSON()
发出的,因此我选择通过提供正则表达式而不是硬编码URL来捕获所有传出请求

我已经搜索了一段时间,试图找出这一点,但仍然没有理解是什么原因导致电话通过。我觉得ES6承诺中的HTTP请求是“在Angular之外”发出的,因此$httpBackend不知道/无法捕获它,尽管如果调用是在开始时的$q承诺内发出的,则情况可能并非如此。有没有人能告诉我为什么要打这个电话,为什么一个简单的超时就可以了?我在这里尝试了
$scope.$apply
$scope.$digest
$httpBackend.flush()
的所有组合,但都没有成功

也许一些代码可以更好地解释它

控制器

function homeController() {
    ...
    var self = this;
    self.getData = function getData() {
        $q.when(user.getUserInformation()).then(function() {
            self.username = user.username;
        });
    };
}
单元测试

...

beforeEach(module('home'));

describe('Controller', function() {
    var $httpBackend, scope, ctrl;

    beforeEach(inject(function(_$httpBackend_, $rootScope, $componentController) {
        $httpBackend = _$httpBackend_;
        scope = $rootScope.$new(); // used to try and call $digest or $apply
        // have also tried whenGET, when('GET', ..), etc...
        $httpBackend.whenJSONP(/.*/)
                    .respond([
                        {
                            "user_information": {
                                "username": "TestUser",
                            }
                        }
                    ]);
        ctrl = $componentController("home");
    }));

    it("should add the username to the controller", function() {
        ctrl.getData(); // make HTTP request
        $httpBackend.flush(); // Error: No pending request to flush !
        expect(ctrl.username).toBe("TestUser");
    });
});

...
然而,出于某些原因,这是可行的:

    it("should add the username to the controller", function() {
        ctrl.getData(); // make HTTP request
        setTimeout(() => {
            // don't even need to call flush, $digest, or $apply...?
            expect(ctrl.username).toBe("TestUser");
        });
    });

多亏了格雷厄姆的评论,我被带进了另一个兔子洞,因为我不了解一些事情,我将在这里总结一下,以防有人在同样的情况下结束

  • 我没有完全理解JSONP是如何工作的。它根本不依赖XmlHttpRequest(请参阅)。我没有试图通过JSONP来处理对这些请求的模拟响应,而是简单地切换了我正在使用的代码上的“debug”标志,该标志禁用了JSONP,因此调用是通过XHR对象进行的(如果需要来自此外部API的实际响应,这将失败)
  • 我没有尝试使用jasmine ajax,而是在jQuery的getJSON上设置了一个间谍,并返回了一个模拟响应。这最终将模拟响应发送到ES6承诺,但由于某种原因,$q承诺对象的
    then
    函数(包装ES6承诺后生成)没有被调用(也没有调用任何其他错误处理函数,甚至
    finally
    )。我还尝试在几乎任何地方调用
    $scope.$apply()
    ,这可能会有所帮助,但没有用

    基本实现(单元测试):

     ...
     spyOn($, 'getJSON').and.callFake(function (url, success) {
         success({"username": "TestUser"}); // send mock data
     });
     ctrl.getData(); // make GET request
     ...
    
     // user.getUserInformation() returns an ES6 promise
     $q.when(user.getUserInformation()).then(function() {
         // this was never being called / reached! (in the unit tests)
     });
    
     ...
     ctrl.getData(); // make GET request
     setTimeout(() => {
         expect(ctrl.username).toBe("TestUser"); // works!
     });
    
    问题(控制器源中):

     ...
     spyOn($, 'getJSON').and.callFake(function (url, success) {
         success({"username": "TestUser"}); // send mock data
     });
     ctrl.getData(); // make GET request
     ...
    
     // user.getUserInformation() returns an ES6 promise
     $q.when(user.getUserInformation()).then(function() {
         // this was never being called / reached! (in the unit tests)
     });
    
     ...
     ctrl.getData(); // make GET request
     setTimeout(() => {
         expect(ctrl.username).toBe("TestUser"); // works!
     });
    
  • 最终,我使用了#2的实现来发送数据,并将断言封装在单元测试中的一个超时内,没有指定持续时间。我意识到这不是最好的,希望这不是应该怎么做的,但经过几个小时的努力,我已经达到了极限,放弃了。如果有人对如何改进这一点有任何想法,或者为什么
    没有被调用,我真的很想听听

    单元测试:

     ...
     spyOn($, 'getJSON').and.callFake(function (url, success) {
         success({"username": "TestUser"}); // send mock data
     });
     ctrl.getData(); // make GET request
     ...
    
     // user.getUserInformation() returns an ES6 promise
     $q.when(user.getUserInformation()).then(function() {
         // this was never being called / reached! (in the unit tests)
     });
    
     ...
     ctrl.getData(); // make GET request
     setTimeout(() => {
         expect(ctrl.username).toBe("TestUser"); // works!
     });
    

  • httpBackend是一个模拟实现,它由angular注入$http服务进行单元测试,如果您不使用$http服务发出请求,您将无法使用httpBackend捕获它