单元测试 – Angular服务测试有什么问题?

我有一个服务调用外部Web服务:

angular.module('myApp.services', [])
.service('autoCmpltDataSvc', function ($http) {
    var innerMatch = function (data) {
        return $.map(data, function (item) {
            return {
                fullName: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
                shortName: item.name,
                itemId: item.geonameId
            };
        });
    };

    this.fetchFromGeonamesDb = function (request, response, matcher) {
        $http({
            method: 'jsonp',
            url: 'http://ws.geonames.org/searchJSON?callback=JSON_CALLBACK',
            params: {
                featureClass: "P",
                style: "full",
                maxRows: 12,
                name_startsWith: request.destName
            }
        }).success(function (data, status) {
            console.log(data);
            response($.map(innerMatch(data.geonames), matcher));
        });
    };
});

我正在尝试测试它是否正确形成了输出,因此我模拟了对真实Web服务的调用.
这是我的单元测试.

describe('Services', function () {

    beforeEach(module('myApp.services'));

    describe('autoCompleteService', function () {
        var $httpBackend, svc;
        var results = [];
        var matcher = function (item) {
            return item;
        };
        var response = function (arr) {
            results = arr;
        };

        beforeEach(inject(function ($injector, autoCmpltDataSvc) {
            svc = autoCmpltDataSvc;
            $httpBackend = $injector.get('$httpBackend');
            $httpBackend.whenJSONP(/searchJSON/).
              respond([
              { name: 'City1', adminName1: 'Region1', countryName: 'Country1', geonameId: 1 },
              { name: 'City2', countryName: 'Country2', geonameId: 2}]);
        }));

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

        it('should return values', function () {
            $httpBackend.expectJSONP(/searchJSON/);
            svc.fetchFromGeonamesDb({ 'destName': 'fra' }, response, matcher);
            $httpBackend.flush();
            expect(results.length).toBe(2);
        });
    });
});

但是测试会产生错误.

         TypeError: Cannot read property 'length' of undefined
            at Function.v.extend.map (C:/Users/kmukhort/Documents/_files/TMate/A
ngularTest/app/lib/jquery-1.8.3.min.js:2:15334)
            at innerMatch (C:/Users/kmukhort/Documents/_files/TMate/AngularTest/
app/js/services.js:8:18)

我认为模拟响应有问题,因为它似乎没有返回数组.
但我无法理解为什么它不返回数组.

提前致谢!

最佳答案 由于彼得培根达尔文,我发现了一个愚蠢的错误.

OK so your success function is expecting your http call to return an
object with a field called geonames, currently your mock is returning
a straight array.

Perhaps you should change your mock to this?

> $httpBackend.whenJSONP(/searchJSON/).
>               respond( { geonames: [
>                 { name: 'City1', adminName1: 'Region1', countryName: 'Country1', geonameId: 1 },
>                 { name: 'City2', countryName: 'Country2', geonameId: 2}]
>               });

https://groups.google.com/forum/#!topic/angular/u-fYR-AC8Ec

点赞