简体   繁体   中英

Spying on something inside a closure - AngularJS Jasmine testing

I have a simple example that I have not been able to solve. While this example is trivial, I want to know how to spy on this $log.error using Jasmine unit testing. I believe closures are the issue even though I am mocking the $log and it would work it it was on not in a closure on the service. Below is code for the Angular Service and Tests. Anyone know how to spy on something inside the closure?:

Angular Code:

afloatApp.service("WebConfigSettingsService", ['$http', '$q', '$log', function ($http, $q, $log) {    
    var getConfigSettings = function () {
        var deferred = $q.defer();

        $http({
            method: 'GET',
            url: '/api/SOMEPATH'
        }).success(function (data, status, headers, config) {
            deferred.resolve(data);
        }).error(function (data, status, headers, config) {
            //THIS IS THE $LOG.ERROR test
            $log.error("Error loading WebConfigSettings");
            deferred.reject(data);
        });

        return deferred.promise;
    };


    var webConfigSettings = getConfigSettings().then(function(data) {
            return {
                classification: angular.lowercase(data.Classification),
                environment: angular.lowercase(data.Environment)
            };
    });

    return webConfigSettings;
}]);

Jasmine Test that Fails

describe('WebConfigSettingsService', function () {
    var webConfigSettingsService, $httpBackend, mockLog, $q, 
        urlExpected = "/api/SOMEPATH",
        serverData = {
            Classification: 'unclassified',
            Environment: 'development'
        };

    beforeEach(module("myApp"));
    beforeEach(inject(function (_$httpBackend_, _$log_, _$q_, _WebConfigSettingsService_) {
        webConfigSettingsService = _WebConfigSettingsService_;
        $httpBackend = _$httpBackend_;
        mockLog = _$log_;
        spyOn(mockLog, 'error');
        $q = _$q_;
        $httpBackend.expectGET(urlExpected);
    }));

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

    it("should log error when http errors out", function () {
        $httpBackend.whenGET("/api/SOMEPATH").respond(500, "Random Error");
        //THIS FAILS.  Note that mockLog.error spy is set in before each
        expect(mockLog.error).toHaveBeenCalled();
    });
});

You're not flushing the backend in your test.

it("should log error when http errors out", function () {
    $httpBackend.whenGET(urlExpected).respond(500, "Random Error");
    $httpBackend.flush();
    expect(mockLog.error).toHaveBeenCalled();
});

When you add that, you will get an error from the flush in the afterEach because there shouldn't be isn't anything left to flush, take that out. Besides, this would cause your verifyNoOutstandingRequest to always pass.

What is the expectGET in the beforeEach for? Seems like it's not needed.

BTW, $log is already mocked by angular-mocks, take a look here for more details: https://docs.angularjs.org/api/ngMock/service/ $log

You could take out the spy and do this:

it("should log error when http errors out", function () {
    $httpBackend.whenGET(urlExpected).respond(500, "Random Error");
    $httpBackend.flush();
    expect(mockLog.error.logs).toContain(["Error loading WebConfigSettings"]);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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