2017-11-17 11 views
4

で賃貸可能演算子をからかう、私はdebounceTime方法を変更するためにヘルパーをしたので、それはTestScheduler使用しています:テストと賃貸可能オペレータ前RxJS 5.5

export function mockDebounceTime(
    scheduler: TestScheduler, 
    overrideTime: number, 
): void { 
    const originalDebounce = Observable.prototype.debounceTime; 

    spyOn(Observable.prototype, 'debounceTime').and.callFake(function(
     time: number, 
    ): void { 
     return originalDebounce.call(
      this, 
      overrideTime, 
      scheduler, 
     ); 
    }); 
} 

したがって、次の観察可能のテストは簡単だった:

を賃貸可能オペレータと
@Effect() 
public filterUpdated$ = this.actions$ 
    .ofType(UPDATE_FILTERS) 
    .debounceTime(DEFAULT_DEBOUNCE_TIME) 
    .mergeMap(action => [...]) 

は、filterUpdated $観察可能ではそのように書かれている:

@Effect() 
public filterUpdated$ = this.actions$ 
    .ofType(UPDATE_FILTERS) 
    .pipe(
     debounceTime(DEFAULT_DEBOUNCE_TIME), 
     mergeMap(action => [...]) 
    ); 

私はもうdebounceTime演算子にパッチを当てることができません! testSchedulerをdebounceTime演算子に渡すにはどうすればよいですか?

+1

[サンプルアプリケーションフォームNgRx](https://github.com/ngrx/platform/tree/master/example-app)をご覧ください。スケジューラは、エフェクトでDIを使用して追加され、別のテストを行うときに追加されます。 –

+0

しかし、私はそのアプローチがあまり好きではありません。テストにのみ使用されるエフェクトにコードを追加したくないのです。このアプローチは、エフェクトをテストするときにTestBedを使用することを意味します。私はしばらくすると、いくつかの選択肢を探します。 –

+0

リンクのThx。私たちはテスト目的のコードを変更する必要はありません:( –

答えて

0

カスタムスケジューラを受け付ける2番目の引数を使用できます。

debounceTime(DEFAULT_DEBOUNCE_TIME, rxTestScheduler), 

すべてのコードが

describe('Service: EffectsService',() => { 
    //setup 
    beforeEach(() => TestBed.configureTestingModule({ 
    EffectsService, 
    { provide: Scheduler, useValue: rxTestScheduler} ] 
    })); 

    //specs 
    it('should update filters using debounce', inject([EffectsService], service => { 
    // your test 
    }); 
}); 
+0

こんにちは、このカスタムスケジューラをテスト中に注入するのが問題です。RxJS 5.4でdebounceTimeを嘲笑するのは簡単でしたが、今は唯一のクリーンな解決策は@ Adrian-Fâciuによって指摘されているようです。 –

+0

あなたの依存関係を明示的にします。これが行く方法です。 –

1

それは注入したり、オペレータにTestSchedulerインスタンスを渡すことが難しい場合は、テストに続いて

import { Scheduler } from 'rxjs/scheduler/Scheduler'; 
import { asap } from 'rxjs/scheduler/asap'; 

@Injectable() 
export class EffectsService { 
    constructor(private scheduler: Scheduler = asap) { } 

    @Effect() 
    public filterUpdated$ = this.actions$ 
    .ofType(UPDATE_FILTERS) 
    .pipe(
     debounceTime(DEFAULT_DEBOUNCE_TIME, this.scheduler), 
     mergeMap(action => [...]) 
    ); 
} 

、この最も簡単な解決策はnowを再バインドすることですscheduleAsyncSchedulerのメソッドのインスタンスと01のメソッドインスタンス。

あなたはこれを手動で行うことができ、次のいずれか

import { async } from "rxjs/Scheduler/async"; 

it("should rebind to the test scheduler",() => { 

    const testScheduler = new TestScheduler(); 
    async.now =() => testScheduler.now(); 
    async.schedule = (work, delay, state) => testScheduler.schedule(work, delay, state); 

    // test something 

    delete async.now; 
    delete async.schedule; 
}); 

それとも、sinonスタブ使用することができます.pipe()が観察プロトタイプに残っているので、あなたはそれであなたのモックの技術を使用することができます

import { async } from "rxjs/Scheduler/async"; 
import * as sinon from "sinon"; 

it("should rebind to the test scheduler",() => { 

    const testScheduler = new TestScheduler(); 
    const stubNow = sinon.stub(async, "now").callsFake(
    () => testScheduler.now() 
); 
    const stubSchedule = sinon.stub(async, "schedule").callsFake(
     (work, delay, state) => testScheduler.schedule(work, delay, state) 
); 

    // test something 

    stubNow.restore(); 
    stubSchedule.restore(); 
}); 
+0

面白い回避策だが、私の意見ではかなり汚い –

+0

ええ、私は同意するが、再利用可能なものにまとめておくのは簡単だ:https://github.com/cartant/rxjs-marbles/blob/master/README.md#dealing -with-deeply-nested-schedulers – cartant

+0

また、私は、RxJS v6では[サブスクリプション時にスケジューラを指定することができる]ことを望んでいます(https://github.com/ReactiveX/rxjs/issues/2935 #issuecomment-336681001)。これを行うことができれば、テストはずっと簡単になります。 – cartant

0

を。

模擬パイプ内では、文字テーブル演算子(oops、今はpipeable operatorsと呼ぶはずです)をそのまま使用できます。

これは、クリーンなCLIアプリケーションのapp.component.spec.tsで使用したコードです。 TestSchedulerを使用するのはおそらく最善の方法ではありませんが、原則が示されています。

import { TestBed, async } from '@angular/core/testing'; 
import { AppComponent } from './app.component'; 
import { Observable } from 'rxjs/Observable'; 
import { debounceTime, take, tap } from 'rxjs/operators'; 
import { TestScheduler } from 'rxjs/Rx'; 

export function mockPipe(...mockArgs) { 
    const originalPipe = Observable.prototype.pipe; 
    spyOn(Observable.prototype, 'pipe').and.callFake(function(...actualArgs) { 
    const args = [...actualArgs]; 
    mockArgs.forEach((mockArg, index) => { 
     if(mockArg) { 
     args[index] = mockArg; 
     } 
    }); 
    return originalPipe.call(this, ...args); 
    }); 
} 

describe('AppComponent',() => { 
    it('should test lettable operators',() => { 
    const scheduler = new TestScheduler(null); 

    // Leave first tap() as-is but mock debounceTime() 
    mockPipe(null, debounceTime(300, scheduler)); 

    const sut = Observable.timer(0, 300).take(10) 
     .pipe(
     tap(x => console.log('before ', x)), 
     debounceTime(300), 
     tap(x => console.log('after ', x)), 
     take(4), 
    ); 
    sut.subscribe((data) => console.log(data)); 
    scheduler.flush(); 
    }); 
}); 
関連する問題