【问题标题】:how to send message from an Observable to an Observer in Unit test如何在单元测试中将消息从 Observable 发送到 Observer
【发布时间】:2019-01-01 11:39:51
【问题描述】:

我有一个 UserManagementService,它公开了一个 BehaviourSubject 的 Observable。

this.userSignInState$ = this.signInStateSubject.asObservable();

userSignInState$ 是公开的,而signInStateSubject 是私有的。

我订阅了nav 组件中的userSignInState$

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 进行单元测试。作为规范的一部分,我想使用signInStateSubject 中的next 并检查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)
  });

【问题讨论】:

    标签: jasmine rxjs angular6 angular-test


    【解决方案1】:

    当我在做单元测试时,我应该嘲笑UserManagementService。去做这个。我创建了一个模拟类,其中包含nav 使用的UserManagementService 的方法和属性。

    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);
      });
    

    【讨论】:

      猜你喜欢
      • 2012-04-04
      • 2020-10-12
      • 2010-09-25
      • 2022-01-03
      • 2016-01-12
      • 1970-01-01
      • 2013-10-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多