问题
I am Jasmine unit testing an angular component, which uses Observables. My component has this lifecycle hook that I am testing:
ngOnInit() {
this.dataService.getCellOEE(this.cell).subscribe(value => this.updateChart(value));
}
I have a test that ensures that getCellOEE has been called, but now I want to check that updateChart is called when the observable resolves with a new value. This is what I have so far:
let fakeCellService = {
getCellOEE: function (value): Observable<Array<IOee>> {
return Observable.of([{ time: moment(), val: 67 }, { time: moment(), val: 78 }]);
}
};
describe('Oee24Component', () => {
let component: Oee24Component;
let service: CellService;
let injector: Injector;
let fixture: ComponentFixture<Oee24Component>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [Oee24Component],
providers: [{ provide: CellService, useValue: fakeCellService }]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(Oee24Component);
component = fixture.componentInstance;
injector = getTestBed();
service = injector.get(CellService)
fixture.detectChanges();
spyOn(service, 'getCellOEE').and.returnValue({ subscribe: () => { } });
spyOn(component, 'updateChart');
});
it('should get cell oee on init', () => {
component.ngOnInit();
expect(service.getCellOEE).toHaveBeenCalled();
});
it('should update chart on new data', () => {
component.ngOnInit();
expect(component.updateChart).toHaveBeenCalled();
});
});
However, I get the error:
chrome 56.0.2924 (Windows 10 0.0.0) Oee24Component should update chart on new data FAILED
Expected spy updateChart to have been called.
Presumably this is a timing issue because the observable hasn't necessarily resolved when the test checks? If that is the case, how do I set this up correctly?
Update:
Here is my component:
@Component({
selector: 'app-oee24',
templateUrl: './oee24.component.html',
styleUrls: ['./oee24.component.css']
})
export class Oee24Component implements OnInit {
public barChartData: any[] = [{ data: [], label: 'OEE' }];
constructor(public dataService: CellService) { }
ngOnInit() {
this.dataService.getCellOEE(this.cell).subscribe(value => this.updateChart(value));
}
updateChart(data: Array<IOee>) {
this.barChartData[0].data = data.map(val => val.val);
}
}
回答1:
Did you ever come up with a solution? What about using the jasmine-marbles
package and the complete
event?
it('should update chart on new data', () => {
const obs$ = cold('--a-|');
spyOn(service, 'getCellOEE').and.returnValue(obs$);
component.ngOnInit();
obs$.subscribe({
complete: () => {
expect(component.updateChart).toHaveBeenCalledWith('a');
}
});
});
回答2:
Not sure if this is the best way to do it, but I've seen it working on a project I'm working on. The approach is basically get a reference to the callback function provided to the subscribe method, and call it manually to simulate the observer emitting a value:
it('should update chart on new data', () => {
component.ngOnInit();
// this is your mocked observable
const obsObject = service.getCellOEE.calls.mostRecent().returnValue;
// expect(obsObject.subscribe).toHaveBeenCalled() should pass
// get the subscribe callback function you provided in your component code
const subscribeCb = obsObject.subscribe.calls.mostRecent().args[0];
// now manually call that callback, you can provide an argument here to mock the "value" returned by the service
subscribeCb();
expect(component.updateChart).toHaveBeenCalled();
});
来源:https://stackoverflow.com/questions/43135596/spy-on-the-result-of-an-observable-subscription-with-jasmine