[英]How to mock Angular BehaviourSubject when Unit Testing
我想在收到BehaviourSubject
更新或 state 更改時測試我的 AppComponent,所以我的目標是在我的AppComponent
authService.authEvent
export class AppComponent implements OnInit, OnDestroy {
user: any
loggedIn = false
constructor(
private router: Router,
private authService: AuthService
) {}
ngOnInit(): void {
this.authService.authEvent.subscribe((user) => {
if (user) {
this.setLoggedIn(user)
} else {
this.setLoggedOut()
}
});
}
setLoggedIn(user: any) {
this.user = user
this.loggedIn = true
}
我的 AuthService 如下(authEvent BehaviourSubject
是我想模擬的):
@Injectable()
export class AuthService {
authEvent = new BehaviorSubject<any>(null);
user: any = {}
constructor(
) {}
setUser(user: any) {
console.log('setUser');
this.user = { ...user }
sessionStorage.setItem('app-user', JSON.stringify(this.user))
this.authEvent.next(this.user)
}
而我的單元測試,我知道這不是模擬BehaviourSubject
的正確方法,但我還沒有找到任何好的例子來做到這一點:
import { BehaviourSubject } from 'rxjs';
export class MockAuthService {
authEvent = new BehaviourSubject<any>();
setUser() {
//mock implementation
}
}
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let mockAuthService;
beforeEach(async(() => {
mockAuthService = jasmine.createSpyObj(['setUser']);
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{ provide: AuthService, useClass: MockAuthService }
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
})
it('should create the app', () => {
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
describe('ngOnInit', () => {
it('should call setLoggedIn user if user received from authEvent', () => {
const mockAuthService = TestBed.get(AuthService);
const userValue = {userName: 'myUser'};
const spy = spyOn(mockAuthService, 'authEvent').and.returnValue(of(userValue));
const spyLoggedOut = spyOn(component, 'setLoggedIn').and.callThrough();
fixture.detectChanges();
expect(setLoggedIn).toHaveBeenCalled();
});
});
});
我將衷心感謝您的幫助!
您可以通過三種方式模擬服務:
獨立地,您選擇以哪種方式模擬服務,您需要將單元測試作為fakeAsync執行,因為您正在使用 Observable 哪些響應不是即時的。
1)像你一樣提供一個模擬實體
import { Subject} from 'rxjs';
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
const mySubject = new Subject();
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{ provide: AuthService, useValue: { authEven: mySubject.asObservable()} }
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
})
it('should create the app', () => {
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
describe('ngOnInit', () => {
it('should call setLoggedIn user if user received from authEvent', fakeAsync(() => {
const spyLoggedOut = spyOn(component, 'setLoggedIn');;
const userValue = {userName: 'myUser'};
component.ngOnInit();
mySubject.next(userValue);
tick();
fixture.detectChanges();
expect(setLoggedIn).toHaveBeenCalled();
flush();
}));
});
});
2) Mocking 組件中Service的實例。
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{ provide: AuthService }
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
})
it('should create the app', () => {
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
describe('ngOnInit', () => {
it('should call setLoggedIn user if user received from authEvent', fakeAsync(() => {
const spyLoggedOut = spyOn(component, 'setLoggedIn');
const userValue = {userName: 'myUser'};
spyOn(component['authService'], 'authEvent').and.returnValue(of(userValue)); //
component.ngOnInit();
tick();
fixture.detectChanges();
expect(setLoggedIn).toHaveBeenCalled();
flush();
}));
});
});
3) 使用 TestBed.get() 獲取服務實例並模擬該服務實例
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let authService: AuthService ;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
providers: [
{ provide: AuthService }
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
authService = TestBed.get(AuthService);
})
it('should create the app', () => {
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
describe('ngOnInit', () => {
it('should call setLoggedIn user if user received from authEvent', fakeAsync(() => {
const spyLoggedOut = spyOn(component, 'setLoggedIn');
const userValue = {userName: 'myUser'};
spyOn(authService, 'authEvent').and.returnValue(of(userValue)); //
component.ngOnInit();
tick();
fixture.detectChanges();
expect(setLoggedIn).toHaveBeenCalled();
flush();
}));
});
});
我更喜歡2) Mocking 組件中的服務實例。 因為它的代碼更少而且更簡單
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.