angularjs服务中的假行为(测试和模拟)

时间:2015-10-04 22:32:26

标签: angularjs unit-testing jasmine karma-runner

我有以下服务:

'use strict';

var app = angular.module('ns.simple-resource', []);

function simpleResource ($q) {
  this.resource;
  this.loading;
  this.list;
  this.element;


  this.cget = function (query) {
    var deferred = $q.defer();
    if (!this.resource) {
      deferred.reject('Resource is not defined');

      return;
    }

    var self = this;
    self.loading = true;
    this.resource.query(query, function (list) {
      self.list = list;
      self.loading = false;
      deferred.resolve(list);
    }, function () {
      self.loading = false;
      deferred.reject('server error');
    });

    return deferred.promise;
  };

  this.get = function (params) {
    var deferred = $q.defer();
    if (!this.resource) {
      deferred.reject('Resource is not defined');

      return;
    }

    var self = this;
    self.loading = true;
    this.resource.get(params, function (element) {
      self.element = element;
      self.loading = false;
      deferred.resolve(element);
    }, function () {
      self.loading = false;
      deferred.reject('server error');
    });

    return deferred.promise;
  };

  this.save = function (params) {
    var deferred = $q.defer();
    if (!this.resource) {
      deferred.reject('Resource is not defined');

      return;
    }

    var self = this;
    self.loading = true;
    this.resource.save(params, function () {
      self.loading = false;
      deferred.resolve();
    }, function () {
      self.loading = false;
      deferred.reject('server error');
    });

    return deferred.promise;
  };

  this.delete = function (params) {
    var deferred = $q.defer();
    if (!this.resource) {
      deferred.reject('Resource is not defined');

      return;
    }

    var self = this;
    self.loading = true;
    this.resource.delete(params, function () {
      self.loading = false;
      deferred.resolve();
    }, function () {
      self.loading = false;
      deferred.reject('server error');
    });

    return deferred.promise;
  };
}

app
  .service('nsResource', simpleResource);

以及以下测试:

'use strict';


var nsResource, child, mockQ = {}, deferred, resourceMock = {};

var list = [
  {id: 1, name: 'John'},
  {id: 2, name: 'Peter'},
  {id: 3, name: 'Juan'}
];

var element = {id: 1, name: 'John'};

describe('simple-resource.js', function () {

  // load the service's module
  beforeEach(module('ns.simple-resource'));

  // instantiate service

  beforeEach(function () {
    deferred = jasmine.createSpyObj('deferred', ['resolve', 'reject']);
    deferred.promise = 'Promise';
    mockQ.defer = function () {
      return deferred;
    };

    nsResource = new simpleResource(mockQ);

    resourceMock = {
      error: false,
      query: function (query, cb, err) {
        if (!this.error) {cb(list);}else{err();}
      },
      get: function (params, cb, err) {
        if (!this.error) {cb(element);}else{err();}
      },
      save: function (params, cb, err) {
        if (!this.error) {cb(element);}else{err();}
      },
      delete: function (params, cb, err) {
        if (!this.error) {cb(element);}else{err();}
      }
    };

    child = {
      cget: function () {
         return nsResource.cget.apply(this, arguments);
      },
      get: function () {
        return nsResource.get.apply(this, arguments);
      },
      save: function () {
        return nsResource.save.apply(this, arguments);
      },
      delete: function () {
        return nsResource.delete.apply(this, arguments);
      }
    };


  });

  // mock child service


  describe('Method: CGET', function () {

    it('returns a promise when resource is defined', function () {
      child.resource = resourceMock;
      expect(child.cget()).toBe('Promise');
    });

    it('rejects the promise on undefined resource', function () {
      child.cget();
      expect(deferred.reject).toHaveBeenCalled();
    });

    it('populates list attribute', function () {
      child.resource = resourceMock;
      child.cget();
      expect(child.list.length).toBe(3);
    });

    it('reject promise on server error', function () {
      resourceMock.error = true;
      child.resource = resourceMock;
      child.cget();
      expect(deferred.reject).toHaveBeenCalled();
    });

  });

  describe('Method: GET', function () {

    it('returns a promise when resource is defined', function () {
      child.resource = resourceMock;

      expect(child.get()).toBe('Promise');
      expect(child.element).toEqual(element);
    });

    it('reject the promise on undefined resource', function () {
      child.get();
      expect(deferred.reject).toHaveBeenCalled();
    });

    it('populates element attribute', function () {
      child.resource = resourceMock;
      child.get();
      expect(Object.keys(child.element).length > 0).toBe(true);
    });

    it('reject promise on server error', function () {
      resourceMock.error = true;
      child.resource = resourceMock;
      child.get();
      expect(deferred.reject).toHaveBeenCalled();
    });

  });

  describe('Method: SAVE', function () {

    it('returns a promise when resource is defined', function () {
      child.resource = resourceMock;
      expect(child.save()).toBe('Promise');
      expect(deferred.resolve).toHaveBeenCalled();
    });

    it('reject the promise on undefined resource', function () {
      child.save();
      expect(deferred.reject).toHaveBeenCalled();
    });

    it('reject promise on server error', function () {
      resourceMock.error = true;
      child.resource = resourceMock;
      child.save();
      expect(deferred.reject).toHaveBeenCalled();
    });

  });

  describe('Method: DELETE', function () {

    it('returns a promise when resource is defined', function () {
      child.resource = resourceMock;
      expect(child.delete()).toBe('Promise');
      expect(deferred.resolve).toHaveBeenCalled();
    });

    it('reject the promise on undefined resource', function () {
      child.delete();
      expect(deferred.reject).toHaveBeenCalled();
    });

    it('reject promise on server error', function () {
      resourceMock.error = true;
      child.resource = resourceMock;
      child.delete();
      expect(deferred.reject).toHaveBeenCalled();
    });

  });

});

如何测试属性“loading”是否已更改?

另外,我如何测试方法从被调用的resourceMock获取,查询,删除和保存?,当我向这些方法添加一个间谍时,每个方法都会失去预期的回调执行。

1 个答案:

答案 0 :(得分:0)

我认为我解决了它。

在测试中添加以下行:

spyOn(resourceMock, 'query').and.callThrough();

请问查询方法的间谍,但会留下当前的实现,儿子模拟可以正常工作,你仍然可以检查是否调用了某个方法。