簡體   English   中英

單元測試時如何模擬 Angular BehaviourSubject

[英]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();
      
    });

  });
  
});


我將衷心感謝您的幫助!

您可以通過三種方式模擬服務:

  1. 像你一樣提供一個 Mock 實體
  2. Mocking 組件中的Service實例。
  3. 使用 TestBed.get() 獲取服務實例並模擬該服務實例

獨立地,您選擇以哪種方式模擬服務,您需要將單元測試作為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM