Angular2测试HTTP服务Put - res.json()不是函数

时间:2016-06-28 14:33:33

标签: angular unit-testing karma-jasmine

我正在尝试使用Karma + Jasmine对我的一项服务的PUT功能进行单元测试。我的GET测试工作正常,但是当我尝试为我的PUT函数运行测试时,我不断收到错误,说res.json()不是函数。我在这里错过了什么?我按照此处所述的测试设置进行了操作:http://chariotsolutions.com/blog/post/testing-http-services-angular-2-jasmine/

服务代码段:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import {FormularyDrug} from '../models/formularydrug';
import { Http, Response, RequestOptions, Headers, Request, RequestMethod} from '@angular/http';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()
export class FormularyDrugService {
    saveFormularyDrug(drug: FormularyDrug) : Observable<FormularyDrug>{
        let body = JSON.stringify({ drug });
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ url: this.formularyDrugURL + drug.DrugId, headers: headers });
        return this.http.put(this.formularyDrugURL + drug.DrugId, body, options)
            .map(this.extractData)
            .catch(this.handleError);
    }
    private extractData(res: Response) {
        let body = res.json();
        return body || [];
    }
    private handleError(error: any) {
        let errMsg = error.message || error.statusText || 'Server error';
        console.error(errMsg);
        return Observable.throw(errMsg);
    }
}

测试类:

import {describe, expect, it, xit, inject, injectAsync, beforeEachProviders} from '@angular/core/testing';
import {provide} from '@angular/core';
import {Headers, HTTP_PROVIDERS, BaseRequestOptions, XHRBackend, Response, ResponseOptions} from '@angular/http';
import {MockBackend, MockConnection} from '@angular/http/testing';

import {FormularyDrugService} from '../services/formularydrugs'
import {FormularyDrug} from '../models/formularydrug'

import 'rxjs/Rx'

describe('FormularyDrugService', () => {

  // All heed this block - it is required so that the test injector
  // is properly set up. Without doing this, you won't get the
  // fake backend injected into Http.

  // Also, you need to inject MockBackend as a provider before you wire
  // it to replace XHRBackend with the provide function!  So this is all
  // extremely important to set up right.
  beforeEachProviders(() => {
      return [
          HTTP_PROVIDERS,
          provide(XHRBackend, {useClass: MockBackend}),
          FormularyDrugService
      ];
  });

  // This test passes without issues
  it('should get list of formularyDrugs', inject([XHRBackend, FormularyDrugService], (mockBackend, drugService) => {
      mockBackend.connections.subscribe(
          (connection: MockConnection) => {
              connection.mockRespond(new Response(
                  new ResponseOptions({
                      body: [{ DrugId: 123 }]
                  }
                  )));
          });

      drugService.getFormularyDrugs().subscribe((drugs: FormularyDrug[]) => {
          expect(drugs.length).toBe(1);
          expect(drugs[0].DrugId).toBe(123);
      });
  }));

  // This returns error -- res.json() is not a function
  it('should save existing formularyDrug', injectAsync([XHRBackend, FormularyDrugService], (mockBackend, drugService) => {
      return new Promise((resolve, reject) => {
          let data: FormularyDrug = new FormularyDrug("BrandName", "GenericName", "TAB", "2mg", "(2mL)", 1);

          mockBackend.connections.subscribe(connection => {
              connection.mockRespond(new ResponseOptions({ body: [{ DrugId: 1 }] }));
          });

          drugService.saveFormularyDrug(data).subscribe((drug: FormularyDrug) => {
              expect(drug).toBeDefined();
              expect(drug.DrugId).toBe(1);
              resolve();
          });
      });
  }), 300);

});

错误讯息:

ERROR: 'res.json is not a function'
Chrome 51.0.2704 (Windows 10 0.0.0): Executed 1 of 2 SUCCESS (0 secs / 0.024 secs)
Chrome 51.0.2704 (Windows 10 0.0.0) FormularyDrugService should save existing formularyDrug FAILED
        Failed: Uncaught (in promise): res.json is not a function
            at ZoneDelegate.invoke (c:/Users/bharris/Source/Repos/Project/UI/node_modules/zone.js/dist/zone.js:323:29)

1 个答案:

答案 0 :(得分:0)

在继续我对该服务的其他单元测试之后,我注意到我在模拟响应中发回的对象是一个数组而不是一个单个对象。这并没有完全解决我的问题,但当我从injectAsync切换到注入时,我能够让测试成功执行。

这是我更新的测试:

it('should save existing formularyDrug', inject([XHRBackend, FormularyDrugService], (mockBackend, drugService) => {
  mockBackend.connections.subscribe(
      (connection: MockConnection) => {
          connection.mockRespond(new Response(
              new ResponseOptions({
                  body: { DrugId: 123 }
              }
              )));
      });

  let data: FormularyDrug = new FormularyDrug("BrandName", "GenericName", "TAB", "2mg", "(2mL)", 1);

  drugService.saveFormularyDrug(data).subscribe((drug: FormularyDrug) => {
      expect(drug).toBeDefined();
      expect(drug.DrugId).toBe(123);
  });
}));