我正在尝试测试在其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()的调用更多复杂功能)
答案 0 :(得分:0)
您的组件在getObs()
中调用ngOnInit()
。您的测试在fixture.detectChanges()
块中调用beforeEach
。对detectChanges()
的第一次调用导致ngOnInit()
被调用。
因此,更改测试中getObs()
的行为不会更改任何内容。太晚了。当执行beforeEach块时,组件已经调用它并进行了预订。
将调用移至测试功能内的第一个fixture.detectChanges()
中,并确保在之前存根服务(告诉getObs()必须返回什么内容)呼叫fixture.detectChanges()
。