无法在单元测试中访问subscribe方法

时间:2017-06-20 10:49:16

标签: json angular unit-testing

我在简单的服务获取方法的单元测试中遇到了一个非常奇怪的问题。我正在使用Angular 4和cli所以karma / jasmine进行测试。

我的服务方式:

getAccounts(): Observable<ApiData> {
    return this.authHttp.get('../../assets/mock_data/productsOverview.json')
      .map(
        data => {
          return JSON.parse(data['_body']);
        },
        err => {
          return err;
        }
      );
  }

这是我的测试用例:

import { TestBed, inject, async } from '@angular/core/testing';
import { Http, BaseRequestOptions, RequestOptions, HttpModule, ConnectionBackend } from '@angular/http';
import { MockBackend, MockConnection } from '@angular/http/testing';
import { AuthHttp, AuthConfig } from 'angular2-jwt';
import { encodeTestToken } from 'angular2-jwt/angular2-jwt-test-helpers';
import { AppModule } from '../app.module';
import { PersonalAccountsService, ApiData } from './personal-accounts.service';
import { Observable } from 'rxjs/Observable';

export function authHttpServiceFactory(http: Http, options: RequestOptions) {
  return new AuthHttp(new AuthConfig({
    headerName: 'Authorization',
    headerPrefix: 'Bearer',
    tokenName: 'token',
    tokenGetter: (() => localStorage.getItem('token')),
    globalHeaders: [
      { 'Content-Type': 'application/json' },
      { 'Ocp-Apim-Subscription-Key': localStorage.getItem('key') }],
  }), http, options);
}

const MyMockedService = {
  method: () => { }
}

describe('PersonalAccountsService', () => {

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        PersonalAccountsService,
        BaseRequestOptions,
        MockBackend,
        {
          provide: Http,
          useFactory: (mockBackend: MockBackend, defaultOptions: BaseRequestOptions) => {
            return new Http(mockBackend, defaultOptions);
          },
          deps: [MockBackend, BaseRequestOptions],
        },
        {
          provide: AuthHttp,
          useFactory: (http) => {
            return new AuthHttp(new AuthConfig({
              tokenName: 'token',
              tokenGetter: (() => encodeTestToken(this)),
              globalHeaders: [{ 'Content-Type': 'application/json' }]
            }), http);
          },
          deps: [Http],
        },
      ],
      imports: [
        HttpModule
      ],
    });
  });

  it('should be created', inject([PersonalAccountsService],
    (service: PersonalAccountsService) => {
      expect(service).toBeTruthy();
    }));

    it('identification', async(
        inject(
            [PersonalAccountsService],
            (service: PersonalAccountsService) => {
              console.log('ENTERS HERE');
                service.getAccounts().subscribe(
                    data => {
                      console.log('NOT ENTERING HERE');
                    },
                    err => {
                      console.log('NOT ENTERING HERE');
                    },
                    () => {
                      console.log('NOT ENTERING HERE')
                    }
                );
            }
        )
    ));
});

为什么会这样?我试图在很长一段时间内把它弄清楚,我甚至不能错误地深入了解。

1 个答案:

答案 0 :(得分:0)

The test likely performs requests but they weren't mocked with MockBackend.

The fact that code relies on third-party services (AuthHttp) makes it integration test rather than unit test.

To keep it as isolated as possible, every unit but tested unit should be mocked or stubbed. The service can be tested in isolation (in this case DI is not tested) or with TestBed:

beforeEach(() => {
  const authHttpMock = jasmine.createSpyObj('authHttp', ['get']);
  TestBed.configureTestingModule({
    providers: [
      { provide: AuthHttp, useValue: authHttpMock }
      ...
});

it('...',  async(inject([PersonalAccountsService, AuthHttp], async (service, authHttpMock) => {
  const responseMock = Observable.of({ _body: ... });
  authHttpMock.get.and.returnValue(responseMock);

  const accounts$ = service.getAccounts();

  expect(authHttpMock.get).toHaveBeenCalledWith(...);

  const accounts = await accounts$.toPromise();

  expect(accounts)...
  ...