jasmine - 如何在单元测试中将消息从 Observable 发送到 Observer
问题描述
我有一个UserManagementService
暴露了一个 Observable 的 a BehaviourSubject
。
this.userSignInState$ = this.signInStateSubject.asObservable();
userSignInState$
是公开的,signInStateSubject
而是私有的。
我订阅了userSignInState$
一个nav
组件。
constructor(public userManagementService: UserManagementService, private fb:FormBuilder, private helper:HelperService) {
this.userSignInStateSubscription = this.userManagementService.userSignInState$.subscribe(
(result:Result)=> {
console.log("In nav - result from user signin state ",result);
let subscribed:UserSigninState = result.additionalInfo;
console.log("new user signin state received:", subscribed);
this.userLoggedIn = subscribed.isSignedIn;
if(subscribed.isSignedIn && subscribed['additional-info'] !== ''){
this.profile = JSON.parse(subscribed['additional-info']) as UserProfileAPI
}
if(!subscribed.isSignedIn && subscribed['additional-info'] !== ''){
// let error:ServerResponseAPI = JSON.parse(subscribed['additional-info']) as ServerResponseAPI
//let errorMessage:string = this.helper.userFriendlyErrorMessage(error);
this.navEvent.emit(new NavContext(subscribed['additional-info']));
}
},
(error:ServerResponseAPI)=>{
console.log("got error from the Observable: ",error);
let errorMessage:string = this.helper.userFriendlyErrorMessage(error);
this.navEvent.emit(new NavContext(errorMessage));
// this.userloggedIn =false;
},
()=>{ //observable complete
console.log("observable completed")
//this.userloggedIn =false;
});
}
我想进行单元测试nav
。作为规范的一部分,我想使用next
并signInStateSubject
检查是否接收到nav
发送的消息next
。但我不能这样做,因为这signInStateSubject
是私人的。如果我signInStateSubject
公开,我可以这样做,但这听起来不对。这
我编写了以下规范,但只有在我signInStateSubject
公开时才有效。
fit('should subscribe to user sign in state observable',()=>{
let userManagementService = TestBed.get(UserManagementService);
let navComponent:NavComponentComponent = component;
console.log('component is ',navComponent);
navComponent.userLoggedIn = false;
let dummyUserProfile = new UserProfileAPI(new User('fn','ln','test@test.com'));
userManagementService.signInStateSubject.next(new Result('success',(new UserSigninState(true,JSON.stringify(dummyUserProfile ))))); //THIS WORKS ONLY IF signInStateSubject IS PUBLIC
expect(navComponent.userLoggedIn).toBe(true)
});
解决方案
当我在做单元测试时,我应该嘲笑UserManagementService
. 去做这个。我创建了一个模拟类,其中包含使用的方法和UserManagementService
属性nav
。
class MockUserManagementService {
signInStateSubject:BehaviorSubject<Result> ;
userSignInState$:Observable<Result>;//naming convention for Streams has $ in the end.
constructor(){
this.signInStateSubject = new BehaviorSubject<Result>(new Result('initial',""));//create Observable. Other components can subscribe to it now to get notifications/values
this.userSignInState$ = this.signInStateSubject.asObservable();
}
getUserProfile(userId: UserID){
console.log('mocked getUserProfile called');
}
}
然后我provide
用嘲笑的班级代替了真实的班级UserManagementClass
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ...],
imports:[...],
providers:[...,
{provide: UserManagementService,useClass:MockUserManagementService},//mock user management service
})
.compileComponents();
}));
规格与之前一样。但这一次,我不需要UserManagementService
公开真实的任何属性,因为服务是模拟的!
it('should subscribe to user sign in state observable',()=>{
let navComponent:NavComponentComponent = component;
let userManagementService = TestBed.get(UserManagementService);//component.userManagementService;
console.log('mock service is ',userManagementService);
console.log('subject is ',userManagementService.signInStateSubject);
console.log('observable is ',userManagementService.userSignInState$);
console.log('nav is ',navComponent);
expect(navComponent.userSignInStateSubscription.closed).toBe(false);
});
it('should should set user as signedIn for successful signin attempt',()=>{
let navComponent:NavComponentComponent = component;
/*The idea of unit test is that UserManagementService might not be available yet
so mock UserManagementService
*/
let userManagementService = TestBed.get(UserManagementService);//component.userManagementService;
console.log('got mocked user management service',userManagementService);
//component.subscribeToUserSignInState();
console.log('component is ',navComponent);
navComponent.userLoggedIn = false;
let dummyUserProfile = new UserProfileAPI(new User('manu','chadha','test@test.com'));
console.log('dummy profile is ',dummyUserProfile);
console.log('dummy profile is JSON stringify',JSON.stringify(dummyUserProfile));
let userSignInState = new UserSigninState(true,JSON.stringify(dummyUserProfile));
console.log('user signin state ',userSignInState);
userManagementService.signInStateSubject.next(new Result('success',userSignInState));
//userManagementService.signInStateSubject.next(new Result('success1',(new UserSigninState(true,JSON.stringify(dummyUserProfile))).toString));
expect(navComponent.userLoggedIn).toBe(true)
});
it('should get user\'s profile',()=>{
let userManagementService = TestBed.get(UserManagementService);
let navComponent:NavComponentComponent = component;
console.log('component is ',navComponent);
navComponent.profile = new UserProfileAPI(new User("fn","ln","test@test.com"));
spyOn(userManagementService,'getUserProfile');
component.onProfileClick();
let userId = new UserID(navComponent.profile['external-profile'].email);
expect(userManagementService.getUserProfile).toHaveBeenCalledWith(userId);
});
推荐阅读
- c++ - 错误:无法使用“const char [34]”类型的左值初始化“const char”类型的返回对象
- python - 有没有其他方法可以解决python中的删除字符?
- r - 使用 R 根据其他列中的匹配将字符串添加到目标字段
- apache-spark - 使用 Spark SQL 将日期时间四舍五入到最近的午夜
- android - paging3 中的 PREPEND 状态是什么意思?
- c++ - 为什么将GStreamer的CMD转成代码会有问题?
- python - Django:MEDIA_ROOT 错误:_getfullpathname:路径应该是字符串、字节或 os.PathLike,而不是元组
- python - 如何通过 keras.load_img 加载多个图像并为 CNN 模型增加每个图像的数据
- c# - 在运行其他代码时检查控制台中的用户输入?
- kubernetes - Seldon:如何使用我自己的 Grafana 和 Prometheus 实例?