Scott Silvi
Scott Silvi

Reputation: 3109

Testing services w/ $httpBackend in AngularJS

I have a service with about a dozen methods hanging off it. I'm setting up my first round of unit tests. Here's a simple example that's working:

it('should have a working getter/setter for SummaryLayoutBn', function() {
    layoutService.setCurrentSummaryLayoutBn('TEST_BN');
    summaryLayoutBn = layoutService.getCurrentSummaryLayoutBn();
    expect(summaryLayoutBn).toEqual('TEST_BN');
}); 

I'm then using $httpBackend to return some mocked json data:

it('should have a working getLayout function', function() {

    $httpBackend.expectGET('/b/json/layout/TEST_BN').respond(defaultSystemLayout);

    expect(layoutCtrlScope.layoutModel.layout).toBeUndefined();

    layoutCtrlScope.loadLayoutFromBn('TEST_BN');

    $httpBackend.flush();

    expect(layoutCtrlScope.layoutModel.layout).toBe(defaultSystemLayout)
});

This is working, but I'm no longer calling my service, I'm calling a function in my controller that calls the service. Is this the right way to do this? It allows me to test that the layoutCtrlScope.layoutModel.layout, but that feels like a test for the controller.

Here is the layout service

getLayout: function (bn) {
    utilService.showLoading();
    var url = baseUrl.generateUrl(baseUrl.layout, bn);
    return $http.get(url).
        success(function (data, status, headers, config) {
            utilService.hideLoading();
        }).
        error(function (data, status, headers, config) {
            errorHandlingService.handleGenericError(status);
        utilService.hideLoading();
        });
}

And the controller function:

$scope.loadLayoutFromBn = function (layoutBn) {
      var layout = layoutService.getLayout(layoutBn);
      layout.then(function (data) {
          $scope.layoutModel.layout = data.data;
      });
}

Upvotes: 1

Views: 803

Answers (1)

pmeskers
pmeskers

Reputation: 88

Ideally, you should be able to unit test the functionality of your service without having to use any methods on your controller.

Looking at your getLayout service function, it seems like you could capture something like this...

describe('getLayout', function() {
  describe('before the request', function() {
    it('shows the loading', function() {
      // assert that utilService.showLoading() has been called
    })
  })

  describe('on success', function() {
    it('hides the loading', function() {
      // assert that utilService.hideLoading() has been called
    })
  })

  describe('on failure', function() {
    it('hides the loading', function() {
      // assert that utilService.hideLoading() has been called
    })

    it('handles errors based on the status', function(){
      // assert that the generic error handler has been called with the expected status
    })
  })
})

Your $httpBackend expecting a GET request would make sure that the URL is correctly generated, and then you would just need to return different responses in your success/failure contexts. In the first assertion, you don't even have to flush any requests.

Upvotes: 0

Related Questions