Angular 我无法使用BehaviorSubject正确配置角度服务测试以发出状态对象

Angular 我无法使用BehaviorSubject正确配置角度服务测试以发出状态对象,angular,unit-testing,rxjs,behaviorsubject,angular-test,Angular,Unit Testing,Rxjs,Behaviorsubject,Angular Test,我有一个服务,它进行api调用,然后在私有状态对象上设置值,然后向行为主体发出更新 @Injectable({ providedIn: 'root' }) export class ExeService { private state: IState = { things: {} }; public things$: BehaviorSubject<{ [key: string]: IThing }> = new BehaviorSubject<{

我有一个服务,它进行api调用,然后在私有状态对象上设置值,然后向行为主体发出更新

@Injectable({
  providedIn: 'root'
})
export class ExeService {
  private state: IState = {
    things: {}  
  };

  public things$: BehaviorSubject<{ [key: string]: IThing }> = new BehaviorSubject<{ [key: string]: IThing }>(this.state.things);

  constructor(
    private http: HttpClient
  ) { }

  public getThings() {
    this.http.get('/api/things').subscribe({
      next: (res) => {
        this.state.things = res;
        this.things$.next(this.state.things)
      }
    })
  }
}
当测试执行时,它实际上执行
getThings()
,并在
req.flush
之前评估对行为主体的订阅。我从概念上理解,在提供所有测试参数之前,不应该评估整个过程。我最终得到了一个404请求
http://localhost:9876/api/things
(karma测试端口),然后它发出测试请求。(我还收到大量来自SASS文件的404警告,试图获取不在我的应用程序目录中的字体文件,但这是另一回事)

为了评估我是否具有预期的值,我首先必须检查行为主体是否具有任何值,从而检查
对象.keys(things).length
。我认为这实际上使测试无效,因为如果服务未能设置它,那么
expect()
将永远不会发生,因此会出现误报。但是,如果我删除它,那么测试将失败,因为初始订阅结果返回
{}


问题:我不明白这是如何工作的,还是我的测试配置完全不正确?

我认为它首先评估订阅,因为您使用的是
行为子对象
。如果您的目的是验证BehaviorSubject是否发出了正确的数据,那么您可以创建一个模拟的
things$
,并断言,例如
things$。接下来使用正确的参数调用了
。现在我还想知道这里是否需要
HttpClientTestingModule
。我认为它会首先评估订阅,因为您使用的是
行为主题。如果您的目的是验证BehaviorSubject是否发出了正确的数据,那么您可以创建一个模拟的
things$
,并断言,例如
things$。接下来使用正确的参数调用了
。现在我还想知道这里是否需要
HttpClientTestingModule
describe('ExeService', () => {
  let injector: TestBed;
  let service: ExeService;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        ExeService
      ],
      imports: [
        HttpClientTestingModule
      ]
    });
    injector = getTestBed();
    service = injector.get(ExeService);
    httpMock = injector.get(HttpTestingController);
  });

  afterEach(() => {
    httpMock.verify();
  });

  it('Should get things', (done) => {

    service.getThings();
    service.things$.subscribe(things => {

      if (Object.keys(things).length) {
        expect(things).toEqual(MockedThings_ApiResponse);
        done();
      }

    });

    const req = httpMock.expectOne(`/api/things`);
    expect(req.request.method).toEqual('GET');
    req.flush(MockedThings_ApiResponse);

  });
});