Angular 2 - Mocking - 没有HTTP提供商 [英] Angular 2 -- Mocking - No Provider for HTTP

查看:144
本文介绍了Angular 2 - Mocking - 没有HTTP提供商的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Angular 2.0.0 - Ionic 2 RC0 - Npm 3.10.8 - Node v4.5.0 - Karma 1.3.0 - Jasmine 2.5.2

我正试图用Karma& amp;茉莉花。现在我到了我遵循一些指南的地步(我是这些测试框架的新手)。但遗憾的是,我在尝试执行测试时遇到错误。

I'm trying to test my application with Karma & Jasmine. Now I got to the point where I followed some guides (I'm new to these testing frameworks). But sadly enough I'm getting an error when trying to execute my test.

我正在尝试测试 EventsPage 它没有 Http 导入,但它调用我的 APICaller.service ,它确实使用了Http。这就是我创建 MockAPICaller 的原因,但它似乎仍然需要 Http (也许是因为它在 APICaller 的构造函数,但我不知道如何修复它。)

I'm trying to test EventsPage which doesn't have an Http import but it calls my APICaller.service which does use Http. That's why I created a MockAPICaller but it seems to still want Http (maybe because it is in APICaller's constructor, but I wouldn't know how to fix that).

所以我怀疑问题在<$ c内$ c> MockAPICaller 但我不确定。

So I suspect the problem is within MockAPICaller but I don't know for sure.

我会发布 MockAPICaller.service APICaller.service EventsPage 和my events.spec.ts 。 (按此顺序,如果你需要/想要你也可以跳过。

I'll post MockAPICaller.service, APICaller.service, EventsPage and my events.spec.ts. (in that order so you could maybe skip along if you need/want to.

import { SpyObject } from './helper';
import { APICaller } from '../apicaller.service';
import Spy = jasmine.Spy;

export class MockAPICaller extends SpyObject {
    getEventsSpy: Spy;
    searchEventSpy:Spy;
    getParticipantSpy:Spy;
    getEventParticipantsSpy:Spy;
    searchEventParticipantSpy:Spy;
    addNewCommentSpy:Spy;
    updateCommentSpy:Spy;
    deleteCommentSpy:Spy;
    getUsernameSpy:Spy;
    presentSuccessMessageSpy:Spy;

    fakeResponse:any;

    constructor(){
        super( APICaller );
        this.fakeResponse = null;
        this.getEventsSpy = this.spy('getEvents').andReturn(this);
        this.searchEventSpy = this.spy('searchEvent').andReturn(this);
        this.getParticipantSpy = this.spy('getParticipant').andReturn(this);
        this.getEventParticipantsSpy = this.spy('getEventParticipant').andReturn(this);
        this.searchEventParticipantSpy = this.spy('searchEventParticipant').andReturn(this);
        this.addNewCommentSpy = this.spy('addNewComment').andReturn(this);
        this.updateCommentSpy = this.spy('updateComment').andReturn(this);
        this.deleteCommentSpy = this.spy('deleteComment').andReturn(this);
        this.getUsernameSpy = this.spy('getUsername').andReturn(this);
        this.presentSuccessMessageSpy = this.spy('presentSuccessMessage').andReturn(this);
    }

    subscribe(callback: any){
        callback(this.fakeResponse);
    }

    setResponse(json:any):void{
        this.fakeResponse = json;
    }
}



APICaller



APICaller

import { Injectable, Inject } from '@angular/core';
import { Http } from '@angular/http';
import { ToastController } from 'ionic-angular';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';

import { Event } from '../models/event.model';
import { Participant } from '../models/participant.model';
import { Comment } from '../models/comment.model';

@Injectable()
export class APICaller {
    http : Http;

    //baseUrl to the REST API
    baseUrl : string = "http://some.correct.url:8080/myAPI";

    constructor(public httpService: Http, public toastCtrl:ToastController) {
        this.http = httpService;
    }


    //-------------------EVENTS-----------------------------------//

    //retrieves all the events
    getEvents() : Observable<Array<Event>> {
        return this.http
        .get(`${ this.baseUrl }/events`)
        .map(response => {
            return response.json();
        });
    }

    //searches events with the provided term
    searchEvent(searchTerm : string) : Observable<Array<Event>> {
        return this.http
        .get(`${ this.baseUrl }/events/search/${ searchTerm }`)
        .map(response => {
            return response.json();
        });
    }

    //--------------------PARTICIPANTS-----------------------------------//

    //retrieves the participant from the REST API
    getParticipant(participantId : number) : Observable<Participant>{
        return this.http
        .get(`${ this.baseUrl }/participants/${ participantId }`)
        .map(response => {
            return response.json();
        });
    }

    getEventParticipants(eventId:number) : Observable<Array<Participant>> {
        return this.http
        .get(`${ this.baseUrl }/events/${ eventId }/participants`)
        .map(response => {
            return response.json();
        });
    }

    //searches for deelnemers with the provided term
    searchEventParticipant(eventId : number, searchTerm : string) : Observable<Array<Participant>> {
        return this.http
        .get(`${ this.baseUrl }/events/${ eventId }/participants/search/${ searchTerm }`)
        .map(response => {
            return response.json();
        });
    }


    //-------------------COMMENTS--------------------------------------//

    //adding a new comment to a participant
    addNewComment(participantId : number, content : string) : Observable<Comment> {
        return this.http
        .post(`${ this.baseUrl }/participants/${ participantId }/addComment`
        ,{
            user: this.getUsername("apikey"),
            content: content
        }).map((response) => {
            this.presentSuccessMessage("Comment added");
            return (response.json());
        });
    }

    //updating an existing comment
    updateComment(participantId : number, commentId : number, content : string) : Observable<Comment> {
        return this.http
        .put(`${ this.baseUrl }/participants/${ participantId }/updateComment/${ commentId }`,{
            id: commentId,
            content: content
        }).map(response => {
            this.presentSuccessMessage("Comment updated");
            return response.json();
        });
    }

    //deleting a currently existing comment
    deleteComment(participantId : number, commentId : number) : Observable<Comment> {
        return this.http
        .delete(`${ this.baseUrl }/participants/${ participantId }/deleteComment/${ commentId }`)
        .map(response => {
            this.presentSuccessMessage("Comment deleted");
            return response.json();
        });
    }

    //presents a successmessage for 3 seconds
    presentSuccessMessage(messageContent : string) {
        //defining the message
        let message = this.toastCtrl
        .create({
            message: messageContent,
            duration: 3000
        });
        //showing the message on screen
        message.present();
    }

    //-------------------USER-------------------------------
    getUsername(someRandomKey : string) : string {
        return "developer";
      /*
        return this.http
        .get(`${ this.baseUrl }/getUsername/${ someRandomKey }`)
        .map(response => {
            return ;
        });
        */
    }
}



EventsPage



EventsPage

import { Component } from '@angular/core';

import { NavController, Loading, LoadingController } from 'ionic-angular';

import { APICaller } from '../../services/apicaller.service';
import { EventDetailComponent } from '../event-detail/event-detail.component';
import { Event } from '../../models/event.model';

/*
  Class for Evenementen Overzicht.
*/
@Component({
  selector: 'events-component',
  templateUrl: 'events.component.html',
  providers: [ APICaller ]
})

 /** -------------------------------------------------------------------------------------- */

export class EventsPage {

//list of all events
public events : Array<Event>;
//the event that has been clicked on the page
public selectedEvent : Event;
//boolean to show 'no events' error message
public noEvents:boolean;

 /** -------------------------------------------------------------------------------------- */

  constructor(public navCtrl : NavController, public apiCaller:APICaller, public loadingCtrl : LoadingController) {
    //retrieve all events --> async method, can't use this.events yet.
    this.getEvents();
  }

  /** -------------------------------------------------------------------------------------- */

  /**Get Events - Sets the 'events' variable to all events found by the API. */
  getEvents(){
    //setup a loadingscreen
    let loading = this.loadingCtrl.create({
      content: "Loading..."
    }); 
    //present the loadingscreen
    loading.present();

    //reset the noEvents boolean.
    this.noEvents = true;

    //call the api and get all events
    this.apiCaller.getEvents()
    .subscribe(response => {
      //response is list of events
      this.events = response;
      //if the event is not empty, set noEvents to false.
      if(this.events.length > 0){
        this.noEvents = false;
      }
      //close the loading message.
      loading.dismiss();
    });
  }

 /** -------------------------------------------------------------------------------------- */

  /**Select Event - Sets the selectedEvent variable to the selected item. */
  selectEvent(event: any, eventObj){
    this.selectedEvent = eventObj;
  }

  /**Search Events - Triggers the API and sets events equal to events found by API*/
  searchEvents(ev){
  //reset noEvents
  this.noEvents = true;
  //if the searchfield is not empty, call api
  if(ev.target.value != ''){
    this.apiCaller.searchEvent(ev.target.value)
    .subscribe(response => {

      this.events = response;
      //
      if(this.events.length > 0){
        this.noEvents = false;

      }
    });
  }else{
    //if the searchfield is empty, get all the events
    this.getEvents();
  }
}

/** -------------------------------------------------------------------------------------- */

/*Cancel Search - clears input field and resets noEvents*/
cancelSearch(ev){
  ev.target.value = "";
  this.noEvents = false;
}
 /** -------------------------------------------------------------------------------------- */

 /**Do Refresh - Refreshes the list of  */
doRefresh(refresher) {
    this.getEvents();

    //giving feedback for user (1 sec instead of faster)
    setTimeout(() => {
      //stop the refresher
      refresher.complete();
    }, 1000);
  }

 /** -------------------------------------------------------------------------------------- */

 /**Go to EventDetail - Pushes the EventDetail page on the navigation stack. */
  goToEventDetail(eventOb: any, eventParam){
    this.navCtrl.push(EventDetailComponent
    , {
      event: eventParam
    });
  }

}
 /** -------------------------------------------------------------------------------------- */



events.spec.ts



events.spec.ts

import { TestBed, inject, tick, fakeAsync } from '@angular/core/testing';
import { BaseRequestOptions, Http, ConnectionBackend, Response, ResponseOptions} from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { FormsModule } from '@angular/forms';
import { NavController, LoadingController } from 'ionic-angular';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { mockNavController } from 'ionic-angular/util/mock-providers';
import { EventsPage } from './events.component';
import { MockAPICaller } from '../../services/mocks/apicaller.service';
import { APICaller } from '../../services/apicaller.service';

describe('Component: EventsComponent', () => {
  let mockAPICaller : MockAPICaller = new MockAPICaller();

  beforeEach(() => {
  TestBed.configureTestingModule({
    declarations: [EventsPage],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],//for usage of Ionic2
    providers: [
      {provide: NavController, useValue: mockNavController },
      {provide: LoadingController, useValue: LoadingController},
      {provide: APICaller, useValue: mockAPICaller}
    ],
    imports: [FormsModule]
  });
  });


  it('should return all events', ()=>{
      let fixture = TestBed.createComponent(EventsPage);
      let eventsPage = fixture.debugElement.componentInstance;
      fixture.detectChanges();

      mockAPICaller.setResponse(JSON.stringify(`{
        id: 4,
        title: 'Weekend',
        eventdate: '24/09/2016',
        kind: 'closed',
        startingtime: '18:00',
        endtime: '21:00',
        description: 'Go home'
      }`));
      let results = eventsPage.getEvents();
      expect(results.length).toBe(1);
      expect(results[0].id).toBe(4);

  });
});


推荐答案

问题是这个

@Component({
  providers: [ APICaller ] <========
})
export class EventsPage {

通过这样,组件将尝试创建自己的<$实例C $ C> APICaller 。这将覆盖您在 TestBed (即模拟)中所做的任何配置。

By having that, the component will try to create its own instance of the APICaller. This overrides any configurations you make in the TestBed (i.e. the mock).

您可以做的是覆盖创建它之前的组件

What you can do is override the component before you create it

beforeEach(() => {
  TestBed.configureTestingModule({})

  TestBed.overrideComponent(EventsPage, {
    set: {
      providers: [
        { provide: APICaller, useValue: mockApiCaller }
      ]
    }
  })
})

另见:

  • Override Component Providers

这篇关于Angular 2 - Mocking - 没有HTTP提供商的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆