(最后这是非常基本的东西,但我花了好几天才弄明白......希望能帮助那里的人节省一些时间:)......)
我遇到了同样的问题,我可以解决它的唯一方法是使用 getter,以便能够在测试时返回模拟值...
因此,在您的服务中,您必须将属性更改为 getter:
private activateProcessReadySubscriptionSource = new Subject<number>();
processReadySubscriptionAnnouced$ () { return this.activateProcessReadySubscriptionSource.asObservable();}
之后,您必须修改访问该属性的方式才能(现在)在您的组件上执行它。
现在您可以访问 .spec.ts 文件中的 observable subscribe 函数...
我现在用代码告诉你我的类似历史:
我有:
/* * * * MyData.service.ts * * * */
// TYPING ASUMPTIONS...
// - DI = [Your defined interface]
// - BS = BehaviorSubject
@Injectable()
export class MyDataService {
private searchToggleSource: BS<DI> = new BS<DI>({ search: false });
public currentToggleSearchStatus: Observable<DI> = this.searchToggleSource.asObservable();
}
/* * * * My.component.ts * * * */
@Component({
selector: 'my-component',
template: './my.component.html',
styleUrls: ['./my.component.css'],
})
export class MyComponent implements OnInit, OnDestroy {
private searchToggleSubscription: Subscription;
public search: boolean;
// DataService being the injected, imported service
constructor(dataService: DataService){ }
ngOnInit(){
this.searchToggleSubscription = this.dataService.currentToggleSearchStatus
.subscribe(
({ search }) => {
this.search = search;
});
}
ngOnDestroy(){
this.searchToggleSubscription.unsubscribe();
}
}
/* * * * My.component.spec.ts * * * */
// ASUMPTIONS
// - USING 'jest'
describe('MyComponent', () => {
let fixture: ComponentFixture<MyComponent>;
let mockDataService;
beforeEach(() => {
mockDataService = createSpyObj('DataService', ['currentToggleSearchStatus', ]);
TestBed.configureTestingModule({
declarations: [
MyComponent,
],
providers: [
{ provide: DataService, useValue: mockDataService },
]
});
fixture = TestBed.createComponent(MyComponent);
});
it('should get state from DataService when ngOnInit', () => {
mockDataService
.currentToggleSearchStatus
.mockReturnValue(of({search: true}));
//... to call ngOnInit()
// ****************** THE ERROR **************************
// **** subscribe is not a function...
// **** Since I have no access to a real Observable from
// **** a fake DataService property...
fixture.detectChanges();
// *** SERIOUSLY I SPEND ALMOST 3 DAYS RESEARCHING AND PLAYING
// *** WITH THE CODE AND WAS NOT ABLE TO FIND/CREATE A SOLUTION...
// *** 'TILL LIGHT CAME IN...
// *******************************************************
expect(fixture.componentInstance.search).toBe(false)
});
});
解决方案...使用吸气剂...我将使用 cmets '-' 来显示“修复”...
/* * * * MyData.service.ts * * * */
// TYPING ASUMPTIONS...
// - DI = [Your defined interface]
// - BS = BehaviorSubject
@Injectable()
export class MyDataService {
private searchToggleSource: BS<DI> = new BS<DI>({ search: false });
//------- CHANGED ---
// public currentToggleSearchStatus: Observable<DI> = this.searchToggleSource.asObservable();
//------- A GETTER ------ (MUST RETURN THE OBSERVABLE SUBJECT)
public currentToggleSearchStatus(){
return this.searchToggleSource.asObservable();
}
}
/* * * * My.component.ts * * * */
@Component({
selector: 'my-component',
template: './my.component.html',
styleUrls: ['./my.component.css'],
})
export class MyComponent implements OnInit, OnDestroy {
private searchToggleSubscription: Subscription;
public search: boolean;
// DataService being the injected, imported service
constructor(dataService: DataService){ }
ngOnInit(){
//------------ CHANGED -------
//this.searchToggleSubscription = this.dataService.currentToggleSearchStatus
//.subscribe(
// ({ search }) => {
// this.search = search;
// });
//------------ EXECUTE THE SERVICE GETTER -------
this.searchToggleSubscription = this.dataService.currentToggleSearchStatus()
.subscribe(
({search}) => {
this.search = search;
}
);
}
ngOnDestroy(){
this.searchToggleSubscription.unsubscribe();
}
}
/* * * * My.component.spec.ts * * * */
// ASUMPTIONS
// - USING 'jest'
describe('MyComponent', () => {
let fixture: ComponentFixture<MyComponent>;
let mockDataService;
beforeEach(() => {
mockDataService = createSpyObj('DataSharingSearchService', ['showHideSearchBar', 'currentToggleSearchStatus', ]);
TestBed.configureTestingModule({
declarations: [
MyComponent,
],
providers: [
{ provide: DataService, useValue: mockDataService },
]
});
fixture = TestBed.createComponent(MyComponent);
});
it('should get state from DataService when ngOnInit', () => {
mockDataService
.currentToggleSearchStatus
.mockReturnValue(of({search: true}));
//... to call ngOnInit()
// ------------- NO ERROR :3!!! -------------------
fixture.detectChanges();
expect(fixture.componentInstance.search).toBe(false)
});
});
*** 注意:jest API 与 jasmine 非常相似...
// jest: jasmine:
// createSpyObj <=> jasmine.createSpyObj
// .mockReturnValue() <=> .and.returnValue()
不要忘记只导入“of”函数,以在您的模拟服务中返回可观察对象...
import { of } from "rxjs/observable/of";