简体   繁体   English

功能单元测试

[英]Unit testing for function

I'm writing a unit test for function getNextPage(). 我正在为功能getNextPage()编写单元测试。 I set the test: expect(this.anotherService.resources).toEqual(3); 我设置了测试:Expect(this.anotherService.resources).toEqual(3); I got error: Expected undefined to equal 3 when running the test. 我收到错误消息:运行测试时,预期undefined等于3。 I logged the anotherService.resources and it returned 3 in console. 我记录了anotherService.resources,它在控制台中返回了3。 Not sure why it's not working. 不知道为什么它不起作用。

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

The value of this.anotherService.resources is still {} in your test because the code in the following then callback is executed after your test runs, asynchronously: 在您的测试中, 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);
})

Although in getItemList you resolve the promise synchronously 尽管在getItemList您可以同步解决promise

getItemList: function(res) {
    var deferred = $q.defer();
    deferred.resolve({
        data: {
            totalRows: 2,
            rows: 3,
        }
    });
    return deferred.promise;
},

... it actually does not call the then function on the promise immediately when you call deferred.resolve . ...实际上,当您调用deferred.resolve时,它不会立即在promise上调用then函数。 When you think of it, that would not make sense either, because the promise must first be returned to the caller before the caller can attach the then call back to it. 当您想到它时,也没有任何意义,因为必须先将诺言返回给呼叫者,然后呼叫者才能附加“ then再回叫给它。 Instead it calls the then callback asynchronously, ie after all currently executing code finishes with an empty call stack. 相反,它异步地调用then回调,即在所有当前执行的代码完成后都带有一个空的调用栈。 This includes your test code! 这包括您的测试代码! As stated in the Angular documentation : Angular文档中所述

then(successCallback, errorCallback, notifyCallback) – regardless of when the promise was or will be resolved or rejected, then calls one of the success or error callbacks asynchronously as soon as the result is available. then(successCallback, errorCallback, notifyCallback) –无论何时或将要解决或拒绝promise, then在结果可用时立即异步调用成功或错误回调之一。

and also in the testing example in the same documentation : 以及同一文档中的测试示例

 // Simulate resolving of promise deferred.resolve(123); // Note that the 'then' function does not get called synchronously. // This is because we want the promise API to always be async, whether or not // it got called synchronously or asynchronously. 

How to test asynchronous code 如何测试异步代码

First, you could let getNextPage return a promise -- the same promise that getItemList returns: 首先,您可以让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
}

And then you can use then on getNextPage() , which will execute in sequence with any other then callbacks attached to it, so after the then callback in the above piece of code. 然后,您可以在getNextPage()上使用then ,它将与附加的其他then回调依次执行,因此在上述代码的then回调之后。

Jasmine's done can then be used to tell Jasmine the test is asynchronous and when it has completed: 然后可以使用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
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM