[英]How to mock Rxjs Subject in Angular
我有一個集中的 DataStore 來保存我的報表連接。 這樣我就可以管理報告連接事件,如 onShow、onError 和 onCancel; 所以實施者不必這樣做。 無論如何。 如何模擬SomeService.doSomething
function 以便它返回我的連接 object 並且它們在 onShow 主題上發出。 請看我的should resolve test data
測試。 我怎樣才能適當地嘲笑這個。
mockSomeService.doSomething.and.callFake(() => {
const response = new ReportManagerConnection();
response.onShow.next({ data: [ {id: 1} ]})
return response
})
這是我的測試。
describe('SomeComponent', () => {
let component: SomeComponent;
let fixture: ComponentFixture<SomeComponent>;
beforeEach(async(() => {
const mockSomeService: jasmine.SpyObj<SomeService> = jasmine.createSpyObj<SomeService>(
'SomeService',
['doSomething']
);
mockSomeService.doSomething.and.callFake(() => {
const response = new ReportManagerConnection();
response.onShow.next({ data: [ {id: 1} ]})
return response
})
TestBed.configureTestingModule({
imports: [ ],
declarations: [SomeComponent],
providers: [
{ provide: SomeService, useValue: mockSomeService },
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should resolve test data', fakeAsync(() => {
component.loadData()
tick()
expect(component.data.length).toBeGreaterThan(0)
}));
});
這是我的代碼
export class ReportManagerConnection {
onShow: Subject<any>
onFinish: Subject<any>
onCancel: Subject<any>
onShow: Subject<any>
onStart: ReplaySubject<any>
onError: ReplaySubject<any>
constructor() {
this.onFinish = new Subject()
this.onCancel = new Subject()
this.onShow = new Subject()
this.onStart = new ReplaySubject()
this.onError = new ReplaySubject()
}
}
@Injectable({
providedIn: 'root'
})
export class ReportStoreService {
connections: Array<ReportManagerConnection> = []
constructor( public http: HttpClient ) { }
send(){
const connection = new ReportManagerConnection()
connections.push(connection)
connection.onShow.asObservable().subscribe((c)=>{
alert('Report Shown')
})
return connection
}
}
@Injectable()
export class SomeService {
constructor( public http: HttpClient, public _ReportStoreService: ReportStoreService ) { }
doSomething(){
const connection = this._ReportStoreService.send()
this.http.get('/api/test').subscribe(c=>{
connection.onShow.next({ data: c })
})
return connection
}
}
@Component({
selector: 'some-component',
templateUrl: './some-component.component.html',
})
export class SomeComponent {
public data = []
constructor(public _SomeService: SomeService) {}
loadData(){
const connection = _SomeService.doSomething()
connection.onShow.asObservable().subscribe((c)=>{
this.data = c.data
})
}
}
嘗試借助 mocking 庫來簡化測試。 例如,如ng-mocks 。
帶有解決方案的沙箱: https://codesandbox.io/s/ecstatic-cache-lv8gk?file=/src/test.spec.ts
describe('SomeComponent', () => {
// configuring TestBed with one line.
beforeEach(() => MockBuilder(SomeComponent).mock(SomeService));
it('should resolve test data', () => {
// creating a mock instance of ReportManagerConnection
// with a preconfigured emit on subscribe to onShow
const reportManagerConnection = MockService(ReportManagerConnection, {
onShow: new BehaviorSubject({ data: [ {id: 1} ]}),
});
// customizing a mock instance of SomeService
MockInstance(SomeService, 'doSomething', () => reportManagerConnection);
// rendering the component
const component = MockRender(SomeComponent).point.componentInstance;
// asserting
expect(component.data.length).toEqual(0);
component.loadData();
expect(component.data.length).toBeGreaterThan(0);
});
});
我在其他地方回答了類似的問題。 請檢查測試用例的這種模擬數據方式:
// In your component.spec file,
@Injectable()
class MockService extends RealService {
yourOriginalServiceMethod() {
return of(mockData);
// Here mockData can be any mocked-data. It should be of whatever the type your
original method in the service returns. Like an object
// 'of' is the RXJS operator. It will turn your mockData to an Observable so that when you run the test case, it will be subscribed without any issue.
}
}
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
realService = TestBed.get(RealService); // this is important to test the subscription error scenario
});
describe('AppComponent', () => { // 2
beforeEach(async(() => { // 3
TestBed.configureTestingModule({
declarations: [
AppComponent
],
providers: [
{
provide: MockService,
useClass: RealService
}
]
}).compileComponents();
}));
// Now your test case,
it("component #yourComponentMethod() method for successful subscription",() => {
spyOn(component, "yourComponentMethod").and.callThrough();
component.yourComponentMethod();
expect(component.yourComponentMethod).toHaveBeenCalled();
// THis method will clear the successful subscription scenario
});
it("component #yourComponentMethod() method for failed subscription",() => {
// This line will call the service and instead of returning mockData, it will fail it.
spyOn(realService, 'yourMethodName').and.returnValue(throwError({status: 500}));
// Rest is the same
spyOn(component, "yourComponentMethod").and.callThrough();
component.yourComponentMethod();
expect(component.yourComponentMethod).toHaveBeenCalled();
// THis method will clear the failed subscription scenario
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.