嗨,我对Angular2,Karma和Jasmine相对较新。目前我正在使用Angular 2 RC4 Jasmine 2.4.x. 我有一个Angular 2服务,定期调用这样的http服务:
getDataFromDb() { return Observable.timer(0, 2000).flatMap(() => {
return this.http.get(this.backendUrl)
.map(this.extractData)
.catch(this.handleError);
});
}
现在我想测试一下这个功能。出于测试目的,我刚刚测试了" http.get"在没有Observable.timer的单独函数上执行:
const mockHttpProvider = {
deps: [MockBackend, BaseRequestOptions],
useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
}
describe('data.service test suite', () => {
var dataFromDbExpected: any;
beforeEachProviders(() => {
return [
DataService,
MockBackend,
BaseRequestOptions,
provide(Http, mockHttpProvider),
];
});
it('http call to obtain data',
inject(
[DataService, MockBackend],
fakeAsync((service: DataService, backend: MockBackend) => {
backend.connections.subscribe((connection: MockConnection) => {
dataFromDbExpected = 'myData';
let mockResponseBody: any = 'myData';
let response = new ResponseOptions({ body: mockResponseBody });
connection.mockRespond(new Response(response));
});
const parsedData$ = service.getDataFromDb()
.subscribe(response => {
console.log(response);
expect(response).toEqual(dataFromDbExpected);
});
})));
});
我显然想用Observable.timer测试整个函数。我想有人可能想要使用rxjs框架中的TestScheduler,但是如何判断只重复计时器函数x次?我无法在打字稿上下文中找到任何使用它的文档。
编辑:我使用的是rxjs 5 beta 6
编辑:为Angular 2.0.0最终版本添加了工作示例:
describe('when getData', () => {
let backend: MockBackend;
let service: MyService;
let fakeData: MyData[];
let response: Response;
let scheduler: TestScheduler;
beforeEach(inject([Http, XHRBackend], (http: Http, be: MockBackend) => {
backend = be;
service = new MyService(http);
fakeData = [{myfake: 'data'}];
let options = new ResponseOptions({ status: 200, body: fakeData });
response = new Response(options);
scheduler = new TestScheduler((a, b) => expect(a).toEqual(b));
const originalTimer = Observable.timer;
spyOn(Observable, 'timer').and.callFake(function (initialDelay, dueTime) {
return originalTimer.call(this, initialDelay, dueTime, scheduler);
});
}));
it('Should do myTest', async(inject([], () => {
backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));
scheduler.schedule(() => {
service.getMyData().subscribe(
myData => {
expect(myData.length).toBe(3,
'should have expected ...');
});
}, 2000, null);
scheduler.flush();
})));
});
答案 0 :(得分:7)
您需要将TestScheduler注入beforeEach部分中的timer方法:
i+1
之后,您可以使用for (int i = 0; i < max.size; ++i) {
printf("%d", i);
if((i+1)%4 == 0)
printf("\n");
}
完全控制时间:
expect -c 'bin/installto.sh /var/www/mail/rc >/dev/null 2>&1'
expect "Do you want to continue? (y/N)"
send "y\n"
interact
您需要beforeEach(function() {
this.scheduler = new TestScheduler();
this.scheduler.maxFrames = 5000; // Define the max timespan of the scheduler
const originalTimer = Observable.timer;
spyOn(Observable, 'timer').and.callFake(function(initialDelay, dueTime) {
return originalTimer.call(this, initialDelay, dueTime, this.scheduler);
});
});
才能启动TestScheduler。
编辑:因此,如果您只想测试X次,请按常规使用计划功能(并使用正确的绝对时间,以毫秒为单位)。
edit2:我添加了缺少的调度程序启动
edit3:我改了它所以应该使用RxJs5
edit4:添加scheduleAbsolute
设置,因为默认值为750毫秒,并且会阻止测试运行时间更长的序列。
答案 1 :(得分:1)
我遇到TestScheduler()
方法的问题,因为schedule()
箭头函数永远不会执行,所以我找到了另一条路径。
Observable.timer
函数只返回一个Observable,所以我从头创建了一个让我完全控制。
首先,为观察者创建一个var:
let timerObserver: Observer<any>;
现在在beforeEach()
创建间谍并让它返回一个Observable。在Observable中,将实例保存到计时器:
beforeEach(() => {
spyOn(Observable, 'timer').and.returnValue(Observable.create(
(observer => {
timerObserver = observer;
})
));
});
在测试中,只需触发Observable:
it('Some Test',()=>{
// do stuff if needed
// trigger the fake timer using the Observer reference
timerObserver.next('');
timerObserver.complete();
expect(somethingToHappenAfterTimerCompletes).toHaveBeenCalled();
});
答案 2 :(得分:0)
我也为此挣扎了一段时间。自从问了这个问题以来,框架显然已经发生了很多变化,所以我认为也许有人会对我的解决方案有所帮助。我的项目使用rxjs 5,茉莉2.8和angular5。
在我的组件中,计时器每分钟用于调用服务中的http-get函数。我的问题是,在使用fakeAsync区域时,从未调用(存根)get函数,并且收到错误消息:“错误:队列中仍存在1个周期性计时器。”
由于计时器不断触发并且在测试结束时没有停止而显示错误。可以通过添加“ discardPeriodicTasks();”来解决。到测试结束,这将导致计时器停止。蜱();可用于伪造时间的流逝,直到下一次通话。我在服务中的get函数上使用了一个间谍,以查看它是否有效:
it(
'should call getTickets from service every .. ms as defined in refreshTime',
fakeAsync(() => {
fixture.detectChanges();
tick();
expect(getTicketsSpy).toHaveBeenCalledTimes(1);
// let 2 * refreshtime pass
tick(2 * component.refreshTime);
expect(getTicketsSpy).toHaveBeenCalledTimes(3);
discardPeriodicTasks();
})
);
refreshTime是我在计时器中使用的参数。我希望这可以防止某人花半天时间来解决这个问题。
答案 3 :(得分:0)
您可以使用fakeAsync()
轻松测试Observable计时器。这是一个显示倒数计时器的组件(使用momentJS持续时间):
@Component({
selector: 'app-timeout-modal',
templateUrl: './timeout-modal.component.html'
})
export class TimeoutModalComponent implements OnInit {
countdownTimer: Observable<number>;
countdownSubscription: Subscription;
durationLeft = moment.duration(60000); // millis - 60 seconds
ngOnInit() {
this.countdownTimer = Observable.timer(0, 1000);
this.countdownSubscription = this.countdownTimer
.do(() => this.durationLeft.subtract(1, 's'))
.takeWhile(seconds => this.durationLeft.asSeconds() >= 0)
.subscribe(() => {
if (this.durationLeft.asSeconds() === 0) {
this.logout();
}
});
}
}
beforeEach(async(() => {
...
}));
beforeEach(() => {
fixture = TestBed.createComponent(TimeoutModalComponent);
component = fixture.componentInstance;
});
it('should show a count down', fakeAsync(() => {
fixture.detectChanges();
expect(component.durationLeft.asSeconds()).toEqual(60);
tick(1000);
fixture.detectChanges();
expect(component.durationLeft.asSeconds()).toEqual(59);
component.countdownSubscription.unsubscribe();
}));