【问题标题】:Angular testing - How to test an observable chain where two services are called?角度测试 - 如何测试调用两个服务的可观察链?
【发布时间】:2020-03-17 16:54:45
【问题描述】:

我正在尝试测试调用 2 个服务的可观察链。我正在尝试测试这两种服务是否只被调用一次。由于这两个服务都返回 observables,我使用 mergeMap 链接调用,如下所示:

app.component.ts

public aliceInChain(): void {
    this.serviceA
      .doSomething()
      .pipe(
        mergeMap(() => {
          return this.serviceB.doSomethingElse();
        })
      )
      .subscribe(r => {
        console.log(r);
      });
  }

在我的规范文件中,我有:

describe("AppComponent", () => {
  let fixture;
  let component;

  beforeEach(async(() => {
    const serviceASpy = jasmine.createSpyObj("serviceA", {
      doSomething: of()
    });

    const serviceBSpy = jasmine.createSpyObj("serviceB", {
      doSomethingElse: of()
    });

    TestBed.configureTestingModule({
      imports: [FormsModule],
      declarations: [AppComponent],
      providers: [
        { provide: ServiceA, useValue: serviceASpy },
        { provide: ServiceB, useValue: serviceBSpy }
      ]
    }).compileComponents();
  }));

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



  fit("should call serviceA and serviceB", done => {

    component.aliceInChain();
    expect(component.serviceA.doSomething).toHaveBeenCalledTimes(1);


  });
});

我可以确保第一个服务被调用,但我如何测试第二个服务是否也被调用?这可能是被测试的方法无效吗?

【问题讨论】:

    标签: angular testing jasmine


    【解决方案1】:

    我不会测试服务是否被调用,而是测试subscribe 中发生的情况。

    describe("AppComponent", () => {
      let fixture;
      let component;
      let serviceASpy;
      let serviceBSpy;
    
      beforeEach(async(() => {
        serviceASpy = jasmine.createSpyObj("serviceA", ['doSomething']);
    
        serviceBSpy = jasmine.createSpyObj("serviceB", ['doSomethingElse']);
    
        TestBed.configureTestingModule({
          imports: [FormsModule],
          declarations: [AppComponent],
          providers: [
            { provide: ServiceA, useValue: serviceASpy },
            { provide: ServiceB, useValue: serviceBSpy }
          ]
        }).compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(AppComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });
    
      fit("should call serviceA and serviceB", done => {
        serviceASpy.doSomething.and.returnValue(of('hello')); // assuming doSomething returns an Observable<string>;
        serviceBSpy.doSomethingElse.and.returnValue(of('hello world')); // assuming doSomething else returns an Observable<string>
        component.aliceInChain();
        // not sure if the next two lines will work
        expect(component.serviceA.doSomething).toHaveBeenCalledTimes(1);
        expect(component.serviceB.doSomethingElse).toHaveBeenCalledTimes(1);
        // assert what should happen in the subscribe
        expect(console.log).toHaveBeenCalledWith('hello world');
        done();
      });
    });
    

    【讨论】:

    • 我必须承认我对你的回答有点困惑,但这可能是因为我在间谍中留下了一些我在本地使用的名字。我已经编辑了我的问题以删除这些值,所以也许你也想更新你的答案。谢谢
    • 这有点奏效,我做了一些更改。我没有使用“完成”,因为测试没有异步回调。控制台的部分也不起作用,因为没有为它创建间谍,这不是测试的目的。对服务的调用现在可以工作了,我能想出的唯一解释是我们在创建间谍时在测试本身而不是全局定义间谍的返回。仍然不确定如何在测试中处理组件方法的异步性。如果有人想加入讨论,将不胜感激。
    • 好吧,这很好,我不是 JavaScript 专家,但我想知道测试的异步特性是如何工作的。我认为在测试环境中,当有subscribe 时,Angular 会给予它优先权并允许它在将控制权交还给测试之前完成。这不是承诺的情况,这就是为什么有一个fixture.whenStable()
    • 目前还不清楚 observables 订阅如何在 Angular 的标准测试环境 (jasmine) 中工作。一些订阅按预期工作,其他订阅则没有,NGXS 在此处引用它 (ngxs.io/recipes/unit-testing)。我还在 jasmine github 中创建了一个问题,以尝试了解它是如何工作的 (github.com/jasmine/jasmine/issues/1804)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    相关资源
    最近更新 更多