简体   繁体   English

Jasmine 带有 toPromise 的 Cold Marble - 永无止境的等待

[英]Jasmine Cold Marble with toPromise - never ending await

I have a debtService which calls backend API with simple HttpClient request.我有一个债务服务,它通过简单的 HttpClient 请求调用后端 API。 It returns an observable.它返回一个可观察对象。 Now, in AppComponent, I'm calling debtService's method to fetch debt.现在,在 AppComponent 中,我调用 debtService 的方法来获取债务。 I want to make sure, that when debt is fetched, also the method called logGetDebtAttempt is being called.我想确保在提取债务时,还会调用名为 logGetDebtAttempt 的方法。

import { Component } from '@angular/core';
import { Observable, Subject, Subscriber, TeardownLogic } from 'rxjs';
import { DebtService } from './services/debt.service';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(private debtService: DebtService) {
  }

  async getDebt() {
    // getNationalDebt() returns Observable<Number>
    await this.debtService.getNationalDebt().toPromise();
    this.logGetDebtAttempt();
  }

  logGetDebtAttempt() {
  }
}

That's why I wrote such test:这就是为什么我写了这样的测试:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { cold } from 'jasmine-marbles';
import { Observable, Subscriber, TeardownLogic } from 'rxjs';
import { AppComponent } from './app.component';
import { DebtService } from './services/debt.service';
import { HttpClientTestingModule } from '@angular/common/http/testing'


const chartServiceStub = {
  getNationalDebt(): Observable<Number> {
    return cold('--x|', { x: 1 });
  }
};

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        RouterTestingModule,
        HttpClientTestingModule
      ],
      declarations: [
        AppComponent
      ],
      providers: [
        { provide: DebtService, useValue: chartServiceStub },
        
      ]
    }).compileComponents();

  });

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
  });

  it('should test', async () => {
    spyOn(component, 'getDebt').and.callThrough();
    spyOn(component, 'logGetDebtAttempt').and.callThrough();

    await component.getDebt();

    expect(component.logGetDebtAttempt).toHaveBeenCalled();
  });
});

When running tests, await component.getDebt();运行测试时,等待 component.getDebt(); never ends and it creates a timeout.永无止境,它会造成超时。

Could someone please explain why is that happening?有人可以解释为什么会这样吗?

Disclaimer: This won't completely answer your question.免责声明:这不会完全回答您的问题。

I am thinking it happens because of the -- syntax where each dash is one millisecond.我认为这是因为每个破折号为一毫秒的--语法。

From my experience, I was never a fan of jasmine-marbles or any marble testing helping library because of those dashes.根据我的经验,由于这些破折号,我从不喜欢jasmine-marbles或任何大理石测试帮助库。

For your scenario, you don't even need marbles.对于您的场景,您甚至不需要弹珠。 You can use of .你可以使用of

import { of } from 'rxjs';
....
const chartServiceStub = {
  getNationalDebt(): Observable<Number> {
    return of(1);
  }
};

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        RouterTestingModule,
        HttpClientTestingModule
      ],
      declarations: [
        AppComponent
      ],
      providers: [
        { provide: DebtService, useValue: chartServiceStub },
        
      ]
    }).compileComponents();

  });

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
  });

  it('should test', async () => {
    spyOn(component, 'getDebt').and.callThrough();
    spyOn(component, 'logGetDebtAttempt').and.callThrough();

    await component.getDebt();

    expect(component.logGetDebtAttempt).toHaveBeenCalled();
  });
});

And also, since it is a .toPromise , I would do a take(1) on it too.而且,因为它是一个.toPromise ,我也会.toPromise做一个take(1) I think having this take , it might help with the marbles scenario as well.我认为有这个take ,它可能与弹珠情况有所帮助。 I know this is an http call most likely and the take is not needed but you could argue that it is better design because if I am going to use await , the stream cannot emit forever.我知道这很可能是一个 http 调用并且不需要take ,但您可能会争辩说它是更好的设计,因为如果我要使用await ,则流不能永远发出。

import { Component } from '@angular/core';
import { Observable, Subject, Subscriber, TeardownLogic } from 'rxjs';
import { DebtService } from './services/debt.service';
import { take } from 'rxjs/operators';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(private debtService: DebtService) {
  }

  async getDebt() {
    // getNationalDebt() returns Observable<Number>
    await this.debtService.getNationalDebt().pipe(take(1)).toPromise();
    this.logGetDebtAttempt();
  }

  logGetDebtAttempt() {
  }
}

I have been searching for similar answers to your question and I just found a paragraph within the rxjs documentation here that reads:我一直在寻找与您的问题类似的答案,我刚刚在此处的 rxjs 文档中找到一段内容,内容如下:

At this time, the TestScheduler can only be used to test code that uses RxJS schedulers - AsyncScheduler , etc. If the code consumes a Promise, for example, it cannot be reliably tested with TestScheduler, but instead should be tested more traditionally.此时, TestScheduler只能用于测试使用 RxJS 调度程序的代码 - AsyncScheduler等。例如,如果代码使用 Promise,则无法使用 TestScheduler 对其进行可靠测试,而应该进行更传统的测试。 See the Known Issues section for more details.有关详细信息,请参阅已知问题部分。

The known issues section goes into slightly more detail about not testing promises. 已知问题部分更详细地介绍了不测试承诺。 But this leads me to believe that if you use promises within your code, you can not use marbles for testing.但这让我相信,如果您在代码中使用 promises,则不能使用弹珠进行测试。

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

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