- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
Angular 2.0.0 - Ionic 2 RC0 - Npm 3.10.8 - Node v4.5.0 - Karma 1.3.0 - Jasmine 2.5.2
我正在尝试使用 Karma & Jasmine 测试我的应用程序。现在我到了遵循一些指南的地步(我是这些测试框架的新手)。但很遗憾,我在尝试执行测试时遇到错误。
我正在尝试测试 EventsPage
,它没有 Http
导入,但它调用了我的 APICaller.service
,它确实使用了 Http .这就是为什么我创建了一个 MockAPICaller
但它似乎仍然需要 Http
(可能是因为它在 APICaller
的构造函数中,但我不会知道如何解决这个问题)。
所以我怀疑问题出在 MockAPICaller
中,但我不确定。
我将发布 MockAPICaller.service
、APICaller.service
、EventsPage
和我的 events.spec.ts
。 (按照这个顺序,如果你需要/想要的话,你可以跳过。
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;
}
}
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 ;
});
*/
}
}
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
});
}
}
/** -------------------------------------------------------------------------------------- */
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 {
有了它,组件将尝试创建它自己的 APICaller
实例。这会覆盖您在 TestBed
(即模拟)中所做的任何配置。
您可以做的是在创建组件之前覆盖它
beforeEach(() => {
TestBed.configureTestingModule({})
TestBed.overrideComponent(EventsPage, {
set: {
providers: [
{ provide: APICaller, useValue: mockApiCaller }
]
}
})
})
另请参阅:
关于unit-testing - Angular 2——模拟——没有 HTTP 提供者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39891904/
我有以下功能: fun process(t: T, call: (U) -> Unit, map: (T) -> U) = call(map(t)) fun processEmpty(t: T,
关闭。这个问题需要更多focused .它目前不接受答案。 想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post . 4年前关闭。 Improve this questi
我正在实现 SVG Tiny 1.1,但我无法理解“用户单元”的概念。 SVG 1.1 规范将每个没有指定单位(例如“mm”、“cm”、“pt”等)的 定义为“用户单位”。 在实现接口(interfa
我正在学习本教程 - http://blog.dasberg.nl/getting-your-frontend-code-quality-in-order/ - 将前端质量指标推送到 SonarQub
我用了 rails new app --skip-test-unit 因为最初,我认为我可以稍后添加测试。 我开发了我的应用程序的很大一部分。 现在,我想添加 Test::Unit 但我找不到任何有关
您如何对由某些报表引擎(例如Crystal Reports或SQL Server Reporting Services)创建的报表进行“单元测试”? 最佳答案 报告的问题类似于GUI的问题。 如果报表
今天在 Proggit 上,我正在阅读题为“Why Unit Testing Is A Waste of Time”的提交的评论线程。 我并不真正关心文章的前提,而是关心 comment对此作出: T
“单元测试”属于白盒测试还是黑盒测试?还是与其他两种测试完全不同? 最佳答案 我觉得这个article by Kent Beck更多地引用 TDD 和单元测试很好地总结了这一点。基本上,这取决于您实际
这是代码: def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet = { foreach(tweet => if(p(el
我打算编写一个抽象类来测试我所有的 DTO 和 DOMAIN 对象。此类将采用可模板对象(通用类型)并使用反射来获取其中的属性类型,并将一些默认值分配给标识的原始类型,稍后将通过访问它们来断言这些类型
我有一个像这样的简单容器特征: trait Handler { def apply[In, Out](in: In): Out } 当我尝试实现它时: new Handler { def ap
为什么这样编译 scala> import scala.concurrent.Future import scala.concurrent.Future scala> val f: Unit = Fu
您使用什么样的实践来使您的代码对单元测试更加友好? 最佳答案 TDD——首先编写测试,强制你要考虑可测试性和帮助编写实际的代码需要的,而不是你认为可能的需要 接口(interface)重构——使得 m
我在elasticsearch中有文本字段,我想在kibana上可视化词云... 第一步,我们需要标记它们,我使用了“标准标记器” ... 使用这种形式的词云可视化结果如下图所示: 但是我需要的是专有
我有以下方法: override def insertAll(notifications: Seq[PushNotificationEncoded]) (i
我的应用程序服务层中有很多方法正在做这样的事情: public void Execute(PlaceOrderOnHoldCommand command) { var order = _rep
一直在使用 Sails.js,但在为 Controller 设计 Jasmine 单元测试时遇到了麻烦。如果这很明显,请原谅我的无知,因为在过去的 3-4 个月里我才深入研究 JavaScript 开
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
在ReKotlin repo README中,有如下代码: data class CounterActionIncrease(val unit: Unit = Unit): Action 代码Unit
我想对一个业务类进行测试,但我遇到了这个问题:其中一个模拟对象与其他类(例如 Sites、URL 和 ComplexObject)有许多依赖关系。 我的问题是:如果我必须在需要测试的方法中使用我的模拟
我是一名优秀的程序员,十分优秀!