繁体   English   中英

Angular + Jasmine - 测试加载的 BehaviorSubject 作为服务中的 Observable

[英]Angular + Jasmine - testing loaded BehaviorSubject as Observable in service

我有一个可注入服务,用于获取超过 HTTP 的用户角色和权限。为了确保 HTTP 调用只进行一次,我在服务中设置了一个 BehaviorSubject 并公开了一个公共 Observable,因此任何注入该服务的组件都可以订阅它检查权限是否已加载。

用户服务.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UserService {

  private _loaded = new BehaviorSubject<boolean>(false);
  public $loaded = this._loaded.asObservable();
  userDetailsUrl = "/serviceurl";

  constructor(private _http: HttpClient) {
    this.getUserDetails();
  }

  getUserDetails() {
    this._http.get(this.userDetailsUrl).subscribe({
      next: (data) => {
        // set permissions...
        this._loaded.next(true);
      }
    });
  }

  // getters for roles and permissions...

一些.component.ts

@Component({...})
export class SomeComponent implements OnInit {

  loadedRoles: Subscription;

  constructor(private _user: UserService) {}

  ngOnInit() {
    this.loadedRoles = this._user.$loaded.subscribe({
      next: (data) => // get roles and permissions to restrict component functionality...
    });
  }
  // ...

在 specfile 中,我希望能够在服务创建后再次调用 getUserDetails 来测试加载的订阅。

用户.服务.spec.ts

describe('SessionService', () => {
  let service: SessionService;
  let httpClient: HttpClient;
  let httpTestingController: HttpTestingController;
  const userDetailsUrl = "/serviceurl";
  const data1 = {
    "roles": ["TESTER"]
  };
  let firstReq;

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule]
    });
    service = TestBed.inject(SessionService);
    httpClient = TestBed.inject(HttpClient);
    httpTestingController = TestBed.inject(HttpTestingController);
    
    firstReq = httpTestingController.expectOne({
      'url': userDetailsUrl,
      'method': 'get'
    });
  }));
  afterEach(() => {
    httpTestingController.verify();
  });

  it('should create and get user details over HTTP', () => {
    expect(service).toBeTruthy();
    expect(firstReq.request.method).toEqual('GET');
  });

  it('should be loaded', () => {
    service.$loaded.subscribe({
      next: (data) => {
        console.log("post load", data);
        expect(data).toBeTruthy(); // since it passes true to the subscription
      },
      error: fail
    });
    service.getUserDetails();
    httpTestingController.expectOne({
      'url': userDetailsUrl,
      'method': 'get'
    }).flush(data1);
  });
  // ...

然而,虽然它确实在调用中更新了 $loaded Observable,但“应该加载”测试失败了,显然是因为 Observable 最初有一个假值,我可以在控制台 output 中看到两次日志语句:

output

Browser application bundle generation complete.
LOG: 'post load', false
Chrome 105.0.0.0 (Windows 10): Executed 1 of 2 SUCCESS (0 secs / 0.022 secs)
LOG: 'post load', true
Chrome 105.0.0.0 (Windows 10): Executed 1 of 2 SUCCESS (0 secs / 0.022 secs)
Chrome 105.0.0.0 (Windows 10) UserService should be loaded FAILED
        Error: Expected false to be truthy.
            at <Jasmine>
            at Object.next (src/app/services/user.service.spec.ts:50:22)
            at ConsumerObserver.next (node_modules/rxjs/dist/esm/internal/Subscriber.js:91:1)
            at SafeSubscriber._next (node_modules/rxjs/dist/esm/internal/Subscriber.js:60:1)
Chrome 105.0.0.0 (Windows 10): Executed 2 of 2 (1 FAILED) (0 secs / 0.032 secs)
Chrome 105.0.0.0 (Windows 10) UserService should be loaded FAILED
        Error: Expected false to be truthy.
            at <Jasmine>
            at Object.next (src/app/services/user.service.spec.ts:50:22)
            at ConsumerObserver.next (node_modules/rxjs/dist/esm/internal/Subscriber.js:91:1)

我在这里错过了什么?

在订阅发生之前,需要根据您的模拟请求调用flush() next()回调是使用 BehaviorSubject 的初始值执行的,因为 Mock 响应在订阅时还没有返回。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM