2

My resource looks something like this.

return $resource(baseURL + 'user',{},{         
     isPermitted: {method: 'POST', isArray:false, params: { regID: @regID} },
     doesExist:   {method: 'GET',  url: baseURL + 'user/doesExist' }
});

I have written Jasmine tests for the same. What I am trying to understand is

  1. Is this the correct way to layout the test (or should i be using something like sinon)

  2. Are these the only test that need to be performed on a resource (or should i be writing a lot more tests. Kindly point out to what other aspects need to be tested)

The test:

describe('UserCheck',function(){

  var $httpBackend, mockUserCheckResource;
  var webServiceBaseURL = 'server.comp.com';

  beforeEach(module('demo'));

    beforeEach(function(){
    angular.mock.inject(function($injector){
      $httpBackend = $injector.get('$httpBackend');
      mockUserCheckResource = $injector.get('UserCheck');
    });
  });

  afterEach(function(){
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  describe('isPermitted',function(){

    var  aObj = {regID:'xxx'};

    it('should issue a POST request to /user',function(){
      var result;
      $httpBackend.expectPOST(webServiceBaseURL + 'user',{regID:'xxx'}).respond(201);

      result = mockUserCheckResource.isPermitted(aObj);
      $httpBackend.flush();
      expect(result.regID).toBeDefined('xxx');      
    });

  });


  describe('doesExist',function(){

    it('should issue a GET request to /user/doesExist',function(){
      var result = {};

      $httpBackend.expectGET(webServiceBaseURL + 'user/doesExist?userID=123').respond({"isPresent":1});

      result = mockUserCheckResource.doesExist({userID:'123'});
      $httpBackend.flush();
      expect(result.isPresent).toBe(1);
    });

  });

);
runtimeZero
  • 26,466
  • 27
  • 73
  • 126
  • 1
    It seems to me that you're testing the functionality of a `$resource`, for which I assume the AngularJS team has already written tests for. – Sunil D. Jun 18 '14 at 14:48
  • so these tests are redundant ? should resources not be tested at all ? – runtimeZero Jun 18 '14 at 15:02
  • Generally, no. Sometimes I add a response handler to a resource, and I then I will write test that uses a resource to test the response handling code. But we shouldn't have to test the resource's behavior itself. – Sunil D. Jun 18 '14 at 15:19
  • Don't. Use resource mocks (as described here: http://stackoverflow.com/questions/18258490/testing-resource-services-in-angularjs ) to test the application logic you write, decoupled from web resources. – Sergiu Paraschiv Jun 18 '14 at 15:29

1 Answers1

0

Two things here : you can test whether $resource properly maps whatever instructions it is given to HTTP calls, which is kind of pointless, and you can also test that your application has a service called UserCheck which maps two methods (isPermitted and doesExist) to the proper HTTP calls. These are different. For the latter — which definitely does make sense — your tests are allright (and offer a good coverage of what your code does in terms of inputs (method calls, HTTP requests), not how it does it.

Still, you can simplify a bit and make your tests clearer :

describe('UserCheck',function(){

  var $httpBackend = undefined;
  var UserCheck = undefined;

  beforeEach(module('demo'));

  beforeEach(inject(function(_$httpBackend_, _UserCheck_) {
    $httpBackend = _$httpBackend;
    UserCheck = _UserCheck_;
  }));

  afterEach(function(){
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  describe('isPermitted',function(){
    it('should issue a POST request to /user',function(){
      $httpBackend.expectPOST('server.comp.com/user').respond(200);

      UserCheck.isPermitted({});
      $httpBackend.flush();
    });
  });


  describe('doesExist',function(){
    it('should issue a GET request to /user/doesExist',function(){
      $httpBackend.expectGET('server.comp.com/user/doesExist?userID=123').respond(200);

      UserCheck.doesExist({userID:'123'});
      $httpBackend.flush();
    });
  });
});

Tips :

  • name your services the same in your code and in your tests
  • don't specify the values returned by $httpBackend unless you want to test how your service/controller will handle them
  • always use plain text URL in your $httpBackend's expectations : it allows to quickly map a method and an URL, and also allows to search across the test (like 'where does this kind or URL gets called ?')
  • no global state, even in tests (except for injected dependencies). If your test grows bigger, it'll be a pain to refactor and handle several different use cases, which is basiclaly the purpose of a unit test file.
LoremIpsum
  • 4,328
  • 1
  • 15
  • 17