用 TypeScript 编写的 Geocoder google 地图服务的业力异步测试

Asynchronous testing in karma for a Geocoder google maps service written in TypeScript

我记下了一个 Google 地图初始化程序服务,它在 dom 中加载 google 地图并公开 google 变量。我还编写了一个地理编码器服务,这是该服务的代码。 geoCodeAddress 方法是逻辑所在,其他部分只是 typescript 样板。当 mapService 公开 google 变量时,我利用它来定义方法并对给定地址进行地理编码,适当地返回供其他开发人员使用的承诺。

module portal.common {

    export interface IGeoCoderService {
        geoCodeAddress(address: string): angular.IPromise<google.maps.GeocoderResult>;
    }

    export class GeoCoderService implements IGeoCoderService {
        public static $inject = ['$q', 'GoogleMapsInitializerService'];

        private $q: angular.IQService;
        public mapService: common.GoogleMapsInitializerService;
        public geocoder: google.maps.Geocoder;

        constructor(private q: angular.IQService, googleMaps: common.GoogleMapsInitializerService) {
            this.mapService = googleMaps;
            this.$q = q;
        }

        public geoCodeAddress(address: string) {
            return this.mapService.init()
                .then(() => {
                    this.geocoder = new google.maps.Geocoder();
                    let deferred = this.$q.defer();
                    this.geocoder.geocode({ address: address }, (results: Array<google.maps.GeocoderResult>, status: google.maps.GeocoderStatus) => {
                        if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
                            deferred.resolve(results);
                        } else {
                            deferred.reject({
                                data: 'No Results'
                            });
                        }
                    });
                    return deferred.promise;
                });
        }
    }

    angular.module('olCommon').service('GeoCoderService', GeoCoderService);
}

我正在尝试使用以下代码测试服务,这主要是我的问题是如何正确测试它?我没有使用给定的代码。第二个测试失败,因为承诺没有解决并且期望 运行 更早,因此在错误中变得未定义。

describe('GeoCoderService', function () {
    var GeoCoderService, $timeout;

    beforeEach(module('olCommon'));

    beforeEach(function () {
        inject(function (_GeoCoderService_, _$timeout_) {
            GeoCoderService = _GeoCoderService_;
            $timeout = _$timeout_;

            spyOn(GeoCoderService, 'geoCodeAddress').and.callThrough();
        });
    });

    it('should initialize correctly', function () {
        expect(GeoCoderService).toBeDefined();
    });

    it('should geocode the address correctly', function () {
        var address = 'Unit 11 35, Crown Street, Granville, NSW 2142';
        var results = undefined;
        GeoCoderService.geoCodeAddress(address).then(function (response) {
            results = response;
        });
        expect(results).toBeDefined();
    });
});

因为 q 永远不会立即调用您的 then,它实际上等待下一个 javascript 周期,使用 setTimeout 和值 0。

并且因为 Angular 人知道这一点,他们创建了 $q 来包装 q 用于测试目的。

您所要做的就是:

rootScope.$apply();

活动更好,在afterEach部分进行。

还有一件事(与问题无关),当在构造函数中定义 private/public/protected 成员时,TypeScript 将为您保存所做操作的样板文件。您的代码应如下所示:

export class GeoCoderService implements IGeoCoderService {
  public geocoder: google.maps.Geocoder;

  public static $inject = ['$q', 'GoogleMapsInitializerService'];
  constructor(private q: angular.IQService, googleMaps: common.GoogleMapsInitializerService) {
  }
  .
  .
  .