angular httpClientTestingModule httpMock给出错误:找到2个请求

时间:2018-04-20 11:03:58

标签: angular angular-httpclient angular-unit-test

我已经编写了第一个测试服务类的测试:

服务类:

import { Injectable } from '@angular/core';
import {HttpClient} from '@angular/common/http'
import {IComment} from "../../models/comments";
import {Observable} from "rxjs/observable";
import { mergeMap } from 'rxjs/operators';

@Injectable()
export class CommentsDataService {

  public _url:string = "../../../../assets/json/comments.json";
  constructor(private http: HttpClient) {  }

  /**
   * Return Sample json for
   * Comment listing.
   * @returns {json)
   */
  getComments():Observable<IComment>
  {
    return this.http.get<IComment>(this._url)
  }

  /**
   *
   * @param commentObj
   */

  saveComment(commentObj){

    console.log(commentObj);

  }

}

规范文件:

import { async, ComponentFixture, TestBed,fakeAsync, tick, inject } from '@angular/core/testing';
import { HttpClientModule, HttpClient, HttpEvent, HttpEventType} from '@angular/common/http';
import { Component,DebugElement} from  "@angular/core";
import 'reflect-metadata';

import {By} from "@angular/platform-browser";
import { FormsModule } from '@angular/forms';
import {of} from 'rxjs/observable/of';
import { ListCommentsComponent } from './list-comments.component';
import {CommentsDataService} from '../../services/comments/comments-data.service'
// import {BaseRequestOptions, RequestOptions,Http, ResponseOptions} from '@angular/http';
// import {MockBackend} from "@angular/http/testing";
import {HttpClientTestingModule,HttpTestingController} from '@angular/common/http/testing';

import { Observable } from 'rxjs/Observable';

describe('ListCommentsComponent', () => {



  let component: ListCommentsComponent;
  let fixture: ComponentFixture<ListCommentsComponent>;
  let debugElement:DebugElement;
  let htmlElement:HTMLElement;
  let addCommentBtn:DebugElement;
  let httpMock: HttpTestingController;
  let commentService:CommentsDataService;
  // let service: CommentsDataService;
  // let backend: MockBackend;


  beforeEach(async(() => {


    TestBed.configureTestingModule({

      imports: [ FormsModule, HttpClientModule, HttpClientTestingModule],

      declarations: [ ListCommentsComponent  ],

      providers: [
        CommentsDataService
        // MockBackend,
        // BaseRequestOptions,
        // {
        //   provide: Http,
        //   useFactory: (backend, options) => new Http(backend, options),
        //   deps: [MockBackend, BaseRequestOptions]
        // }
      ]
      // providers:[HttpClientModule, HttpClient]


    })
      .compileComponents();
    httpMock = TestBed.get(HttpTestingController);
    commentService = TestBed.get(CommentsDataService);

    /*
        // Get the MockBackend
        backend = TestBed.get(MockBackend);

        // Returns a service with the MockBackend so we can test with dummy responses
        service = TestBed.get(CommentsDataService);
    */


  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(ListCommentsComponent);
    component = fixture.componentInstance;

    fixture.detectChanges();


  });


  fit('should have a defined component', () => {
    expect(component).toBeDefined();
  });


  fit(
    'should return comments',() => {

      const mockComments = [
        {
          "id": "123",
          "root_id": "234",
          "target_id": "2",
          "object": "Nice!",
          "actor": "user:123",
          "time_stamp": "2 min ago",
          "profile_image": "/../../assets/images/no-user.png",
          "first_name": "john",
          "comment": [
            {
              "id": "124",
              "root_id": "234",
              "target_id": "3",
              "object": "Well!!",
              "actor": "user:123",
              "time_stamp": "2 min ago",
              "first_name": "john",
              "profile_image": "/../../assets/images/no-user.png"
            },
            {
              "id": "125",
              "root_id": "234",
              "target_id": "3",
              "object": "Great!",
              "actor": "user:125",
              "time_stamp": "2 min ago",
              "first_name": "john",
              "profile_image": "/../../assets/images/no-user.png"
            }
          ]
        },

      ];

      commentService.getComments().subscribe((comments) => {

        expect(comments).toBe('json');
        expect(comments).toContain('comments');


      });

      const mockReq = httpMock.expectOne(commentService._url);

      // expect(mockReq.cancelled).toBeFalsy();
      expect(mockReq.request.method).toEqual('GET');
      mockReq.flush(mockComments);

      httpMock.verify();

    }
  );

});

我收到错误,我在互联网上找不到任何解决方案,因为我不熟悉 httpClientTestingModule 实际上是如何工作的 这些代码行意味着我无法调试或理解错误,因此无能为力。

commentService.getComments().subscribe((comments) => {

        expect(comments).toBe('json');
        expect(comments).toContain('comments');


      });

      const mockReq = httpMock.expectOne(commentService._url);

      // expect(mockReq.cancelled).toBeFalsy();
      expect(mockReq.request.method).toEqual('GET');
      mockReq.flush(mockComments);

      httpMock.verify();

错误:

  

错误:预期一个匹配的条件请求&#34;匹配网址:   ../../../../assets/json/comments.json",找到了2个请求。

我在服务文件中发出请求的Comments.json文件:

[{ "id":"123",
  "root_id":"234",
  "target_id": "2",
  "object":"Nice!",
  "actor":"user:123",
  "time_stamp": "2 min ago",
  "profile_image":"/../../assets/images/no-user.png",
  "first_name" : "john",
  "comment":[
    {
      "id": "124",
      "root_id":"234",
      "target_id":"3",
      "object":"Well!!",
      "actor":"user:123",
      "time_stamp": "2 min ago",
      "first_name" : "john",
      "profile_image":"/../../assets/images/no-user.png"
    },
    {
      "id": "125",
      "root_id":"234",
      "target_id":"3",
      "object":"Great!",
      "actor":"user:125",
      "time_stamp":"2 min ago",
      "first_name" : "john",
      "profile_image":"/../../assets/images/no-user.png"
    }
  ]
},
  {
    "id":"126",
    "root_id":"234",
    "target_id": "2",
    "object":"Super.",
    "actor":"user:124",
    "time_stamp": "2 min ago",
    "first_name" : "Jill",
    "profile_image":"/../../assets/images/no-user.png",
    "comment":[
      {
        "id": "234",
        "root_id":"234",
        "target_id":"",
        "object":"Cool.",
        "actor":"user:123",
        "first_name" : "john",
        "profile_image":"/../../assets/images/no-user.png"

      },
      {
        "id": "236",
        "root_id":"234",
        "target_id":"3",
        "object":"hiii.",
        "actor":"user:123",
        "first_name" : "jack",
        "profile_image":"/../../assets/images/no-user.png"

      }
    ]
  },  {
  "id":"345",
  "root_id":"234",
  "target_id": "12",
  "object":"Interesting.",
  "actor":"user:124",
  "time_stamp": "2 min ago",
  "first_name" : "john",
  "profile_image":"/../../assets/images/no-user.png"
},  {
  "id":"444",
  "root_id":"234",
  "target_id": "12",
  "actor":"user:125",
  "object":"Cool.",
  "time_stamp": "2 min ago",
  "first_name" : "Simon",
  "profile_image":"/../../assets/images/no-user.png"
},
  {
    "id":"567",
    "root_id":"234",
    "target_id": "12",
    "object":"Last Comment..",
    "actor":"user:125",
    "time_stamp": "2 min ago",
    "first_name" : "jack",
    "profile_image":"/../../assets/images/no-user.png"
  }
]

1 个答案:

答案 0 :(得分:2)

如果我的回答不如前一个完整,我很抱歉,但我正在打电话。如果您需要更多解释,请在周一通知我,我将有一台计算机来帮助您。

我在这里可以看到你正在测试一个组件。

在单元测试中,您应该测试您正在使用的功能。由于http调用是由您的服务进行的,因此您应该测试它们在您的服务测试中是否正确,而不是在您的组件中。

这意味着在您的组件中,只有在调用正确的服务方法时才会测试。这是通过使用茉莉花间谍来完成的。

这也意味着您可以模拟您的服务。如果你模拟你的服务,你将不必模拟它的依赖,因为你将提供一个没有依赖的简单对象。

要模拟服务,您需要在模拟中提供您在组件中使用的所有属性。从我看到的,你只使用getComments,所以让我们模拟:

const serviceMock = {
  provide: YourServiceName, 
  useValue: {
    getComments: () => Observable.of(null)
  }  
};

这是模拟的格式。它必须尊重某些条件:

  • 如前所述,它必须包含所有使用的属性。
  • 这些属性必须具有相同的签名。这里,getComments是一个函数,它返回一个可观察的注释(每种类型都为null),就像在你的服务中一样。

现在,你可以把这个模拟器放到你的试验台上:

providers: [serviceMock]

获取服务实例的逻辑与我在上一个问题中解释的相同。

现在,您可以编写一个测试来检查组件是否正确调用该服务!你只需要做一个间谍,调用你的组件功能,并期待。

spyOn(serviceInstance, 'getComments').and.callThrough(); // use returnValue(Observable.of(commentsMock)) instead of callThrough() if you want to test your logic made on the value returned by the function
component.functionCall();
expect(serviceInstance.getComments).toHaveBeenCalled();

瞧!