角度测试-可观察到不同的返回值

时间:2019-08-26 21:09:34

标签: angular jasmine

我正在尝试测试在其ngOnInit上订阅了服务中可观察对象的组件,并根据从可观察对象获得的值来更改组件的行为。我将问题简化为这些代码。

组件:

import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';

@Component({
  selector: 'app-root',
  template: `
  <div>
    <h3>currentValue is {{currentValue}}</h3>
    <div>
      <button (click)="changeTo(true)">true</button>
      <button (click)="changeTo(false)">false</button>
    </div>
  </div>
  `,
  styleUrls: ['./app.component.less']
})
export class AppComponent implements OnInit {
  public currentValue: boolean;

  constructor(
    private appService: AppService
  ) { }

  ngOnInit() {
    this.appService.getObs().subscribe(newValue => this.currentValue = newValue);
  }

  changeTo(value: boolean) {
    this.appService.setObs(value);
  }
}

服务:

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable({
    providedIn: 'root'
})
export class AppService {
    private obs = new BehaviorSubject<boolean>(false);

    getObs(): Observable<boolean> {
        return this.obs.asObservable();
    }

    setObs(value: boolean): void {
        this.obs.next(value);
    }
}

测试:

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { AppService } from './app.service';
import { of } from 'rxjs';

describe('AppComponent', () => {
  let mockAppService = jasmine.createSpyObj(['setObs', 'getObs']);

  let app: AppComponent
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
      providers: [
        { provide: AppService, useValue: mockAppService }
      ]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    mockAppService.getObs.and.returnValue(of(false));
    app = fixture.debugElement.componentInstance;
    fixture.detectChanges();
  });

  it('should create the app', () => {

    expect(app).toBeTruthy(); // pass
  });

  it('should set currentValue to false', () => {

    expect(app.currentValue).toBe(false); // pass
  });

  it('should change currentValue to true', () => 
    mockAppService.// some how to do next(true)
    fixture.detectChanges();

    expect(app.currentValue).toBe(true); // 
  });
});

我希望有一种简单的方法来控制模拟操作返回的值。我想在测试之间更改值并测试每个选项。

我看到了茉莉花大理石的选择,但是看起来很复杂。有谁知道一种简单的方法吗?

编辑:我希望能够在观测台上调用next(),而无需调用setObs(可以说它是私有的,实际上在我的应用中我没有setObs函数,对next()的调用更多复杂功能)

1 个答案:

答案 0 :(得分:0)

您的组件在getObs()中调用ngOnInit()。您的测试在fixture.detectChanges()块中调用beforeEach。对detectChanges()的第一次调用导致ngOnInit()被调用。

因此,更改测试中getObs()的行为不会更改任何内容。太晚了。当执行beforeEach块时,组件已经调用它并进行了预订。

将调用移至测试功能内的第一个fixture.detectChanges() 中,并确保在之前存根服务(告诉getObs()必须返回什么内容)呼叫fixture.detectChanges()