【问题标题】:RxJS: why does subscribing makes no differenceRxJS:为什么订阅没有区别
【发布时间】:2019-07-29 10:46:33
【问题描述】:

考虑以下服务示例

export class AuthService {
  private observableCache: { [key: string]: Observable<boolean> } = {};
  private resourceCache: { [key: string]: boolean } = {};

  constructor(private userService: UserService) { }

  isGranted(resource): Observable<boolean> {
    if (this.resourceCache[resource]) {
      return of(this.resourceCache[resource]);
    }

    if (this.observableCache[role]) {
      return this.observableCache[role];
    }

    this.observableCache[resource] = this.userService
        .getCurrentUser()
        .pipe(map((user: User) => user.canAccess(resource)))
        .pipe(share());

    return this.observableCache[resource];
  }
}

在此服务中,我正在检查是否允许用户查看特定资源。

这就是我尝试测试它的方式

describe('AuthService', () => {
  let service: AuthService;
  let userService: any;

  beforeEach(() => {
    userService = jasmine.createSpyObj('UserService', ['getCurrentUser']);
    service = new AuthGuardService(userService);
  });

  describe('isGranted', () => {
    const user: User = {id: 123};

    beforeEach(() => {
      userService.getCurrentUser.and.returnValue(
        hot('-^u', { u: user })
      );
    });

    it('should prove response being cached', () => {
      service.isGranted('dashboard').subscribe();
      service.isGranted('dashboard').subscribe();

      expect(userService.getCurrentUser).toHaveBeenCalledTimes(1);
    });
  });
});

测试的目的是检查资源缓存是否有效。但我注意到的是,如果我替换以下 sn-p

  service.isGranted('dashboard').subscribe();
  service.isGranted('dashboard').subscribe();

简单

  service.isGranted('dashboard');
  service.isGranted('dashboard');

测试仍然有效,我是 RxJS 和大理石测试的新手,但据我所知,Observable 在订阅之前不应该工作。

问题 - 为什么它是双向的?

【问题讨论】:

  • 您不是在测试是否创建了 Observable 链。您只是在测试是否调用了userService.getCurrentUser,并且每次调用isGranted 时都会调用它。所以这与 RxJS 无关。
  • 为什么userService.getCurrentUser 在没有订阅订阅的情况下被执行?正如我从 RxJS 文档中得到的那样,计算只发生在每个订阅的观察者身上
  • 与 RxJS 无关。当您调用 isGranted 时,您调用该方法,就像任何其他 JavaScript 代码中的任何其他方法一样。
  • @martin 你能提供一个这个测试应该是什么样子的例子吗?谢谢

标签: angular unit-testing rxjs observable jasmine-marbles


【解决方案1】:

测试使用的代码是异步的,请尝试使用fakeAsynctick 运行它

it('should prove response being cached', fakeAsync(() => {
  service.isGranted('dashboard').subscribe();
  service.isGranted('dashboard').subscribe();
  tick();
  expect(userService.getCurrentUser).toHaveBeenCalledTimes(1);
}));

查看https://angular.io/guide/testing#component-with-async-service了解更多信息。

【讨论】:

  • 谢谢!这个测试用例通过了,我的也一样!您能否扩展您的答案并提供解释?现在我正在寻找答案而不是代码 sn-ps
  • 看看 JavaScript 中的事件循环,特别是宏任务和微任务。在异步调用中,Javascript 可能会在任务之间“切换”,让你不知道什么时候执行哪个。 “service.isGranted('dashboard').subscribe()” 启动一个微任务。使用“fakeAsync”,您可以将整个代码放入一种沙箱中。并使用“tick()”告诉沙箱执行所有打开的微任务。如果你不这样做,你的单元测试可能在微任务执行之前就完成了。热烈的问候 Jan
猜你喜欢
  • 2021-10-30
  • 2017-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-12
  • 2015-02-24
  • 1970-01-01
相关资源
最近更新 更多