首页 文章

单元测试功能

提问于
浏览
1

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

Test

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

Code:

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

1 回答

  • 4

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

    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 时,它实际上不会立即调用承诺上的 then 函数 . 当你想到它时,这也没有意义,因为在调用者可以将 then 回调附加到它之前,必须首先将promise返回给调用者 . 相反,它异步调用 then 回调,即在所有当前正在执行的代码完成后使用空调用堆栈 . 这包括您的测试代码!如Angular documentation所述:

    then(successCallback,errorCallback,notifyCallback) - 无论何时或将要解析或拒绝承诺,只要结果可用,就会异步调用其中一个成功或错误回调 .

    以及testing example in the same documentation

    //模拟承诺的解决
    deferred.resolve(123);
    //请注意,'then'函数不会被同步调用 .
    //这是因为我们希望promise API始终是异步的,无论是否
    //它是同步或异步调用的 .

    如何测试异步代码

    首先,您可以让 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
    }
    

    然后你可以在 then 上使用 then ,它将与附加到它的任何其他 then 回调一起执行,所以在上面的代码中回调 then 之后 .

    然后可以使用Jasmine的done告诉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
        });
    });
    

相关问题