使用模拟后端测试Angular2服务

时间:2015-09-28 18:44:06

标签: http dependency-injection typescript angular

首先:我知道Angular2处于alpha状态且频繁更改。

我正在使用Angular2。有一个带有 http 依赖关系的可注入服务,我想使用模拟后端进行测试。该应用程序启动时该服务正常运行,但我没有运气写测试并让模拟后端响应。有任何见解,在我错过的测试设置或实现中是否有明显的东西?

服务/ core.ts:

import { Injectable } from 'angular2/angular2';
import { Http } from 'angular2/http';

@Injectable()
export class CoreService {

    constructor(public http:Http) {}

    getStatus() {
        return this.http.get('/api/status')
            .toRx()
            .map(res => res.json());
    }
}

服务/ core_spec.ts:

import {
    AsyncTestCompleter,
    TestComponentBuilder,
    By,
    beforeEach,
    ddescribe,
    describe,
    el,
    expect,
    iit,
    inject,
    it,
    xit
} from 'angular2/test';
import { MockBackend, MockConnection, BaseRequestOptions, Http, Response } from 'angular2/http';
import { Injector, bind } from 'angular2/angular2';
import { ObservableWrapper } from 'angular2/src/core/facade/async'

import { CoreService } from 'public/services/core'

export function main() {

    describe('public/services/core', () => {

        let backend: MockBackend;
        let response: Response;
        let coreService: CoreService;
        let injector: Injector;

        afterEach(() => backend.verifyNoPendingRequests());

        it('should get status', inject([AsyncTestCompleter], (async) => {

            injector = Injector.resolveAndCreate([
                BaseRequestOptions,
                MockBackend,
                bind(Http).toFactory((backend, options) => {
                    return new Http(backend, options)
                }, [MockBackend, BaseRequestOptions]),
                bind(CoreService).toFactory((http) => {
                    return new CoreService(http);
                }, [Http])
            ]);

            backend = injector.get(MockBackend);
            coreService = injector.get(CoreService);
            response = new Response('foo');

            ObservableWrapper.subscribe<MockConnection>(backend.connections, c => {
                expect(c.request.url).toBe('/api/status');
                c.mockRespond(response);
            });

            // attempt #1: fails because res argument is undefined
            coreService.getStatus().subscribe(res => {
                expect(res).toBe('');
                async.done();
            });

            // attempt #2: fails because emitter.observer is not a function
            ObservableWrapper.subscribe(coreService.getStatus(), res => {
                expect(res).toBe('');
                async.done();
            });

        }));
    });

}

相关: https://github.com/angular/angular/issues/3502 https://github.com/angular/angular/issues/3530

2 个答案:

答案 0 :(得分:6)

我在寻找测试技巧的同时找到了这个主题,但我无法直接回答这个问题......

这个基于Angular RC.1

使用Mock后端测试服务

假设您的服务是:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

@Injectable()
export class CoreService {
  constructor(private http: Http) {}

  getStatus() {
    return this.http.get('/api/status');
  }
}

对上述服务的测试将如下所示:

import {
  beforeEach,
  beforeEachProviders,
  describe,
  expect,
  inject,
  it,
} from '@angular/core/testing';

import { provide } from '@angular/core';
import { BaseRequestOptions, Response, ResponseOptions } from '@angular/http';
import { MockBackend, MockConnection } from '@angular/http/testing';

describe('Http', () => {

  beforeEachProviders(() => [
    CoreService,
    BaseRequestOptions,
    MockBackend,
    provide(Http, {
      useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
        return new Http(backend, defaultOptions);
      },
      deps: [MockBackend, BaseRequestOptions]
    })
  ]);

  beforeEach(inject([MockBackend], (backend: MockBackend) => {
    const baseResponse = new Response(new ResponseOptions({ body: 'status' }));
    backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
  }));

  it('should return response when subscribed to getStatus',
    inject([CoreService], (coreService: CoreService) => {
      coreService.getStatus().subscribe((res: Response) => {
        expect(res.text()).toBe('status');
      });
    })
  );

})

你真正需要注意的是在beforeEachProviders中进行适当的嘲弄。测试本身非常简单,最终订阅了服务方法。

注意:不要忘记先设置基本提供程序:

import { setBaseTestProviders } from '@angular/core/testing';
import {
  TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS,
  TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
} from '@angular/platform-browser-dynamic/testing';

setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);

答案 1 :(得分:3)

自从提出这个问题以来,我们确实升级到Angular2 RC 1.我们的进口看起来像Wojciech Kwiatek(感谢您的回答!)但我们的测试策略略有不同。我们想要在请求和响应上断言。我们使用beforeEachProviders()而不是beforeEach(),我们创建了自己的注入器,并保存了对被测试服务和模拟后端的引用。这允许我们对请求进行断言并管理测试内部的响应,并允许我们在每次测试后使用verifyNoPendingRequests()方法。

describe('core-service', () => {

  let service: CoreService;
  let backend: MockBackend;

  beforeEach(() => {
    injector = ReflectiveInjector.resolveAndCreate(<any> [
        CoreService,
        BaseRequestOptions,
        MockBackend,
        provide(Http, {
            useFactory: (mockBackend, defaultOptions) => new Http(mockBackend, defaultOptions),
            deps: [MockBackend, BaseRequestOptions]
        })
    ]);

    service = <CoreService> injector.get(CoreService);
    backend = <MockBackend> injector.get(MockBackend);
  });

  afterEach(() => backend.verifyNoPendingRequests());

  it('should get status', () => {

    backend.connections.subscribe((c: MockConnection) => {
      expect(c.request.url).toEqual('api/status');
      c.mockRespond(new Response(new ResponseOptions({ body: 'all is well' })));
    });

    service.getStatus().subscribe((status) => {
      expect(status).toEqual('all is well');
    });

  }));
});

编辑:Plunker更新为RC2。 https://plnkr.co/edit/nlvUZVhKEr8d2mz8KQah?p=preview