zoukankan      html  css  js  c++  java
  • [Unit Testing Angular] RxJS Marble testing for Component

    Component:

    import { Component, OnInit } from "@angular/core";
    import { TwainService } from "../twain.service";
    import { Observable, of } from "rxjs";
    import { startWith, catchError } from "rxjs/operators";
    
    @Component({
      selector: "twain",
      templateUrl: "./twain.component.html",
      styleUrls: ["./twain.component.scss"]
    })
    export class TwainComponent implements OnInit {
      errorMessage: string;
      quote: Observable<any>;
      constructor(private twainService: TwainService) {}
    
      ngOnInit() {
        this.getQuote();
      }
      getQuote() {
        this.errorMessage = "";
        this.quote = this.twainService.getQuote().pipe(
          startWith("..."),
          catchError((err: any) => {
            // Wait a turn because errorMessage already set once this turn
            setTimeout(() => (this.errorMessage = err.message || err.toString()));
            return of("..."); // reset message to placeholder
          })
        );
      }
    }
    <p class="twain">
      <i>{{ quote | async }}</i>
    </p>
    <button (click)="getQuote()">Next quote</button>
    <p class="error" *ngIf="errorMessage">{{ errorMessage }}</p>

    Testing code:

    import {
      async,
      ComponentFixture,
      TestBed,
      fakeAsync,
      tick
    } from "@angular/core/testing";
    import { of, throwError } from "rxjs";
    import { TwainComponent } from "./twain.component";
    import { TwainService } from "../twain.service";
    import { cold, getTestScheduler } from "jasmine-marbles";
    
    fdescribe("TwainComponent", () => {
      let component: TwainComponent;
      let fixture: ComponentFixture<TwainComponent>;
      let quoteEl;
      let testQuote;
      let getQuoteSpy;
    
      beforeEach(() => {
        testQuote = "Test Quote";
    
        // Create a fake TwainService object with a `getQuote()` spy
        const twainService = jasmine.createSpyObj("TwainService", ["getQuote"]);
        // Make the spy return a synchronous Observable with the test data
        getQuoteSpy = twainService.getQuote.and.returnValue(of(testQuote));
    
        TestBed.configureTestingModule({
          declarations: [TwainComponent],
          providers: [{ provide: TwainService, useValue: twainService }]
        });
        fixture = TestBed.createComponent(TwainComponent);
        component = fixture.componentInstance;
        quoteEl = fixture.nativeElement.querySelector(".twain");
      });
    
      it("should show quote after getQuote (marbles)", () => {
        // observable test quote value and complete(), after delay
        const q$ = cold("-a|", { a: testQuote });
        getQuoteSpy.and.returnValue(q$);
    
        fixture.detectChanges(); // ngOnInit()
        expect(quoteEl.textContent).toBe("...", "should show placeholder");
    
        getTestScheduler().flush(); // flush the observables
    
        fixture.detectChanges(); // update view
    
        expect(quoteEl.textContent).toBe(testQuote, "should show quote");
        expect(component.errorMessage).toBe("", "should not show error");
      });
    
      it("should display error when TwainService fails", fakeAsync(() => {
        // observable error after delay
        const q$ = cold("---#|", null, new Error("TwainService test failure"));
        getQuoteSpy.and.returnValue(q$);
    
        fixture.detectChanges(); // ngOnInit()
        expect(quoteEl.textContent).toBe("...", "should show placeholder");
    
        getTestScheduler().flush(); // flush the observables
        tick(); // component shows error after a setTimeout()
        fixture.detectChanges(); // update error message
    
        expect(component.errorMessage).toMatch(
          /test failure/,
          "should display error"
        );
        expect(quoteEl.textContent).toBe("...", "should show placeholder");
      }));
    });

    The beauty of marble testing is in the visual definition of the observable streams. This test defines a cold observable that waits three frames (---), emits a value (x), and completes (|). In the second argument you map the value marker (x) to the emitted value (testQuote).

    const q$ = cold("-a|", { a: testQuote });

    For error case:

    const q$ = cold('---#|', null, new Error('TwainService test failure'));

    This is a cold observable that waits three frames and then emits an error, The hash (#) indicates the timing of the error that is specified in the third argument. The second argument is null because the observable never emits a value.

  • 相关阅读:
    R语言学习——数据分析
    java学习——类之YuanZhu
    java学习——类之YuanZhu
    java学习——构造类之3!+5!=126
    C# WebQQ协议群发机器人(二)
    Unity5.1 新的网络引擎UNET(七) UNET 单人游戏转换为多人
    转:Oracle GoldenGate学习之Goldengate介绍
    cvReadTrainData
    使用Handler在子线程中更新UI
    初识MVC
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12403675.html
Copyright © 2011-2022 走看看