首页 > 解决方案 > Angular 单元测试模拟重播主题

问题描述

我有一个带有重播主题的服务。

export class UserService {
  public userChanged: ReplaySubject<User> = new ReplaySubject<User>();

...
public getUser(userId?): void {
    ...
    this.http.get(url, httpOptions).pipe(
      catchError(this.handleError('getUser', null, 'Couldn\'t get user', options))
    ).subscribe( (user: User) => {

       this.userChanged.next(user);

    });
  }

我的组件订阅userChanged.

this.userService.userChanged.subscribe((user) => {
  this.user = user;
});

现在,我想UserService在组件测试中模拟我的:

1个选项在Angular中测试Observables

import { of } from 'rxjs';
...
    const userServiceSpy = jasmine.createSpyObj('UserService', {'userChanged': of({_id: '1'}) });

或 2 个选项)

    const userServiceSpy = jasmine.createSpyObj('UserService', {'userChanged': () => of({_id: '1'}) });

或 3 选项角度测试教程

const userServiceSpy = jasmine.createSpyObj('UserService', ['userChanged']});
const userChangedSpy = userServiceSpy.userChanged.and.returnValue( of({_id: '1'})  );

+

TestBed.configureTestingModule({
  ...
  providers: [
    ...
    {provide: UserService, useValue: userServiceSpy}
  ],
  schemas: [NO_ERRORS_SCHEMA]
})

给我这个错误:

this.userService.userChanged.subscribe is not a function

不应该of返回一个 Observable 来订阅吗?

问题:如何模拟这个?

标签: angularunit-testing

解决方案


createSpyObj用于创建方法的间谍。您可以将其用于getUser.UserService

userChanged只是类的属性。你不需要间谍。

您可以做的只是创建一个返回主题的模拟对象:

const userChanged = new Subject();

 providers: [
    ...
    {provide: UserService, useValue: { userChanged }}
  ],

{ userChanged }等于{ userChanged: userChanged }

然后,在您的beforeEach块中,您将发出一个新的用户实例:

//...
beforeEach(() => {
   const myUser = new User(...)
   userChanged.next(myUser)
})

我建议在beforeEach块中执行此操作以避免不同规格之间的副作用。

 providers: [
    ...
    {provide: UserService, useValue: { userChanged: of({id: 1}) }}
  ],

of另一种做同样事情的方法是使用与您在示例中相同的方法创建可观察对象。


如果你真的想监视subscribe方法,你可以在它上面创建 spy:

spyOn(userChanged, 'subscribe')


如果要spyObject与属性混合,可以使用扩展运算符:

const spyObj = {
  ... jasmine.createSpyObj('MyObject', ['spyMethod']),
  myProperty: true,
};

spyObj.spyMethod();

expect(spyObj.spyMethod).toHaveBeenCalled();
expect(spyObj.myProperty).toBeTrue();

推荐阅读