Javascript 功能的单元测试

Javascript 功能的单元测试,javascript,function,unit-testing,jasmine,Javascript,Function,Unit Testing,Jasmine,我正在为函数getNextPage()编写一个单元测试。 我设置了测试:expect(this.anotherService.resources).toEqual(3); 我得到一个错误:运行测试时,预期undefined等于3。 我记录了另一个service.resources,它在控制台中返回了3。 不知道为什么它不起作用 测试 describe('Test for someController', function() { beforeEach(function() { mod

我正在为函数getNextPage()编写一个单元测试。 我设置了测试:expect(this.anotherService.resources).toEqual(3); 我得到一个错误:运行测试时,预期undefined等于3。 我记录了另一个service.resources,它在控制台中返回了3。 不知道为什么它不起作用

测试

describe('Test for someController', function() {
  beforeEach(function() {
    module('someApp');
    return inject(function($injector) {
      var $controller;
      var $q = $injector.get('$q');

      this.rootScope = $injector.get('$rootScope');
      $controller = $injector.get('$controller');
      this.state = $injector.get('$state');
      this.stateParams = {
        id: 1,
      }
      this.location = $injector.get('$location')
      this.timeout = $injector.get('$timeout')
      this.upload = $injector.get('$upload')
      this.someService = {
        getItemList: function(res) {
          var deferred = $q.defer();
          deferred.resolve({
            data: {
              totalRows: 2,
              rows: 3,
            }
          });
          return deferred.promise;
        },
        pages: jasmine.createSpy(),

        memberIds: 1,
        currEng: []
      };
      this.anotherService = {
        resources: {}
      };
      this.scope = this.rootScope.$new();
      this.controller = $controller('someController', {
        '$scope': this.scope,
        '$rootScope': this.rootScope,
        '$state': this.state,
        '$stateParams': this.stateParams,
        '$location': this.location,
        '$timeout': this.timeout,
        '$upload': this.upload,
        'someService': this.someService,
      });
      this.scope.$digest();
    });
  });

  it('should be defined', function() {
    expect(this.controller).toBeDefined();
    expect(this.scope.ss).toEqual(this.someService);
  });

  it('should run the getNextPage function', function() {
    this.scope.getNextPage();
    this.scope.$digest();
    console.log(this.anotherService.resources);        // this is showing as Object {} in terminal
    expect(this.anotherService.resources).toEqual(3);
  });
代码:

someapp.controller('someController', resource);
resource.$inject = ['$scope', '$state', '$stateParams', '$location','$timeout','$upload', 'someService', 'anotherService'];
function resource($scope, $state, $stateParams,$location,$timeout, $upload, someService, anotherService) {

      $scope.fileReaderSupported = window.FileReader != null && (window.FileAPI == null || FileAPI.html5 != false);

      $scope.ss = EsomeService;
      $scope.as = anotherService;
      $scope.getNextPage = getNextPage;


      function getNextPage(options){

        var o = options || {selected:1};
        var start = (o.selected-1)*10 || 0;
        someService.currPage = o.selected;

        someService.getItemList($stateParams.id,'F', start).then(function (res){
          anotherService.resources = res.data.rows;
          console.log(anotherService.resources)   // this shows LOG: 3 in terminal
          someService.numResults = res.data.totalRows;
          someService.pageNumbers = someService.pages(res.data.totalRows,10);
        })
      }
});

this.anotherService.resources
的值在测试中仍然是
{}
,因为以下
然后
回调中的代码在测试运行后异步执行:

someService.getItemList($stateParams.id,'F', start).then(function (res){
    anotherService.resources = res.data.rows;
    console.log(anotherService.resources)
    someService.numResults = res.data.totalRows;
    someService.pageNumbers = someService.pages(res.data.totalRows,10);
})
尽管在
getItemList
中,您可以同步解析承诺

getItemList: function(res) {
    var deferred = $q.defer();
    deferred.resolve({
        data: {
            totalRows: 2,
            rows: 3,
        }
    });
    return deferred.promise;
},
。。。实际上,当您调用
deferred.resolve时,它不会立即调用promise上的
then
函数。当您想到它时,这也没有意义,因为在调用方可以附加
调用之前,必须首先将承诺返回给调用方,然后才能将
调用返回给它。相反,它先异步调用
,然后异步调用
回调,即在所有当前执行的代码都以空调用堆栈完成之后。这包括您的测试代码!如合同所述:

then(successCallback,errorCallback,notifyCallback)
–无论承诺何时被解决或拒绝,
一旦结果可用,
就会异步调用其中一个成功或错误回调

以及:

如何测试异步代码 首先,您可以让
getNextPage
返回一个承诺——与
getItemList
返回的承诺相同:

function getNextPage(options){
    var o = options || {selected:1};
    var start = (o.selected-1)*10 || 0;
    someService.currPage = o.selected;
    // store the promise in a variable
    var prom = someService.getItemList($stateParams.id,'F', start);
    prom.then(function (res){
        anotherService.resources = res.data.rows;
        console.log(anotherService.resources)   // this shows LOG: 3 in terminal
        someService.numResults = res.data.totalRows;
        someService.pageNumbers = someService.pages(res.data.totalRows,10);
    });
    return prom; // return that promise
}
然后您可以在
getNextPage()
上使用
then
,它将与附加到它的任何其他
then
回调一起按顺序执行,因此在
之后,在上述代码段中使用
then
回调

然后可以使用Jasmine's告诉Jasmine测试是异步的,测试完成后:

// The presence of the `done` parameter indicates to Jasmine that 
// the test is asynchronous 
it('should run the getNextPage function', function(done) { 
    this.scope.getNextPage().then(function () {
        this.scope.$digest();
        console.log(this.anotherService.resources);
        expect(this.anotherService.resources).toEqual(3);
        done(); // indicate to Jasmine that the asynchronous test has completed
    });
});

你需要等待承诺。你为什么要使用承诺?我试过使用。bing(这个)它返回给我一个不同的错误。TypeError:undefined不是一个对象(评估'this.scope.getNextPage'),它可能表明
已经不是到达
it
调用时您所认为的那样。你能解释一下你想要的
这个
是什么吗,也许能提供调用
的完整上下文吗?我想你是对的,我尝试了console.log(this.anotherService.resources)并将其返回给我一个对象。我已将someService中的数据设置为totalRows:2和rows:3。我希望行通过promise,并为另一个service.resource返回3。您能否在问题中提供更多代码,以便我查看您将测试放置在何处?
console.log(此………)
的结果取决于您将其放置的位置。带有
this
的每一行代码都是上下文敏感的,因此在您的问题中,请确保代码上下文是清楚的,否则我们就看不清了。这是一个更完整的代码版本,希望事情会更有意义。谢谢
// The presence of the `done` parameter indicates to Jasmine that 
// the test is asynchronous 
it('should run the getNextPage function', function(done) { 
    this.scope.getNextPage().then(function () {
        this.scope.$digest();
        console.log(this.anotherService.resources);
        expect(this.anotherService.resources).toEqual(3);
        done(); // indicate to Jasmine that the asynchronous test has completed
    });
});