【问题标题】:Angular/Jasmine testing with deffered promises带有延迟承诺的 Angular/Jasmine 测试
【发布时间】:2014-11-16 23:21:24
【问题描述】:

我正在使用 angular 和 jasmine 的组合测试控制器,但我不完全确定是否使用延迟承诺。

这是我的规范代码。

describe('Controller Tests', function(){
    var scope, searchAPI;

    beforeEach(function(){
        var mockSearchAPI = {};
        module('myApp', function($provide){
            $provide.value('searchAPI', mockSearchAPI);
        });
    });

    inject(function($q){
        var testData = {"message":"hi"};
        mockSearchAPI.executeSearch = function(){
            var defer = $q.defer();
            defer.resolve(testData);
            return defer.promise;
        };
    });

    beforeEach('Main Search Controller Tests', function(){

        function($controller, $rootScope, _searchAPI_){
            scope = $rootScope.$new();
            searchAPI = _searchAPI_;
            $controller('MainSearchCtrl', function(){
                $scope: scope,
                searchAPI: searchAPI
            });
            scope.$digest();
        }
    });

    it('should return a promise correctly', function(){
        var field = "testfield";
        var value = "testvalue";
        var pageNumber = 1;
        var promise = scope.processQueryByField(field, value, pageNumber);

        //THIS LINE IS GIVING ME '{}'
        alert(promise); 
    });

});

我不确定为什么我“警告”的那一行会输出“{}”。不应该是我在注入函数中定义为“testData”的数据结构吗?我不确定这里发生了什么。我尝试了很多解决方案。

我的控制器代码基本上是服务的包装器

$scope.processQueryByField = function(field, value, pageNumber){
    return searchAPI.executeSearch(field, value, pageNumber);
}

我不应该只接收我在注入器代码中定义的值吗?

【问题讨论】:

  • searchAPI.executeSearch 返回一个承诺,对吗?所以最终processQueryByField 也会返回一个数据不正确的承诺?那么你想要设定的期望是什么?更重要的是,您需要掌握$rootScope 并在调用函数后应用摘要,然后再设置期望值。
  • 我只是想确保我的模拟设置正确(即返回一个承诺),并且我能够进行更复杂的测试。在设置期望值之前获取 $rootScope 并应用摘要是什么意思?
  • it('should invoke execute search', function(){ spyOn(mockSearchAPI,'executeSearch'); var field = "testfield"; var value = "testvalue"; var pageNumber = 1; scope.processQueryByField(field, value, pageNumber); expect(mockSearchAPI.executeSearch).toHaveBeenCalled(); expect(mockSearchAPI.executeSearch).toHaveBeenCalledWith(field, value, pageNumber); });
  • 我会详细说明我的意思。

标签: angularjs unit-testing jasmine deferred angular-promise


【解决方案1】:

我不确定你想用 Promise 对象设置什么期望,你不需要测试一个 Promise 是否被解决,而是你需要测试数据会发生什么when承诺已解决。

例子:-

更改您的模拟以简化:-

inject(function($q){
    var testData = {"message":"hi"};
    mockSearchAPI.executeSearch = function(){
       return $q.when(testData);
    };
});

只是为了演示,我在您的控制器中添加了一个解析数据的方法:-

.controller('MainSearchCtrl', ['$scope','searchAPI', function ($scope, searchAPI) {
        //At this point placing this method on scope is useless
        $scope.processQueryByField = function(field, value, pageNumber){
           return searchAPI.executeSearch(field, value, pageNumber);
        }
        //This when invoked will update the searchResults in the model.
        $scope.populateData = function(){
          $scope.processQueryByField(1,1,1).then(function(data){
            $scope.searchResults = data;
          })
        }
    }]);

期望 #1:- 测试调用方法时是否使用预期参数调用 api 方法。

   it('should invoke execute search', function(){
     //Set up a spy on your mock api method
      spyOn(mockSearchAPI,'executeSearch'); 
      var field = "testfield";
      var value = "testvalue";
      var pageNumber = 1;
      scope.processQueryByField(field, value, pageNumber); //invoke scope method with args
      //Test if the mock api method has been called
      expect(mockSearchAPI.executeSearch).toHaveBeenCalled();          
      //test if it has been called with expected arguments.
      expect(mockSearchAPI.executeSearch).toHaveBeenCalledWith(field, value, pageNumber); 
    });

期望 #2:- 在 promise 解决时测试数据是否正确填充。

it('should return a promise correctly', function(){
    var field = "testfield";
    var value = "testvalue";
    var pageNumber = 1;

    var promise = scope.processQueryByField(field, value, pageNumber);
    //This is a useless expectation
    expect(promise).toBeDefined();


    scope.populateData();
    $rootScope.$digest(); //<-- Apply digest cycle, so the promise is resolved
    expect(scope.searchResults).toBeDefined();
    expect(scope.searchResults.message).toEqual("hi");
});

Test Demo

【讨论】:

  • 谢谢,我很确定这会让我走向正确的方向。
  • @PSL + 1 额外的努力。我真的从你的回答中学到了很多东西。谢谢。
  • @PSL 你应该习惯它。我经常在“不太受欢迎的标签”中回答,有时我会花半个小时或更长时间来回答这个问题,因为 OP 刚刚消失,这个答案甚至没有被接受。没有意见,没有赞成票。就是这样,但我们总是有很好的练习并获得经验——这比分数重要得多。
  • @alecxe 是的,说得好!!我有时会在角度和其他一些标签中感受到这种感觉。角度标签中有趣的事情是,有时我得到的票数超过了一些非常简单的答案应得的票数。:D
  • @PSL,对不起?我以为我接受了你的回答是正确的。还有什么我可以做的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-11
  • 2015-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多