简体   繁体   English

来自 Angular 组件 rxjs 订阅的单元测试服务调用

[英]Unit testing service calls from an Angular component rxjs subscription

I have this Angular (v13) code in a component:我在一个组件中有这个 Angular (v13) 代码:

export class MyComp {
  destroy$ = new Subject<void>();
  submits$ = new Subject<MyFormState>(); // .next() in the template

  ngOnInit(){
    this.submits$.pipe(
      takeUntil(this.destroy$)
    ).subscribe(formState => this.service.doSomething(formState));
  }
}

and I am trying to unit test it using jasmine spy object:我正在尝试使用 jasmine 间谍 object 对其进行单元测试:

describe('MyComp', () => {
  let submits$ = new Subject<MyFormState>();
  let mock = jasmine.createSpyObj('MyService', [ 'doSomething' ]);

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ MyComp ],
      providers: [
        { provide: MyService, useValue: mock },
      ],
    });
  });

  it('should be called when clicking the button', () => {
    const f: MyFormState = { name: 'my name' };
    component.submits$.next(formState);

    waitForAsync(() => {
      expect(mock.doSomething).toHaveBeenCalledWith(f); // <-- false positives, anything passes
    });
  });
});

I have also tried another async pattern我也尝试过另一种异步模式

it('should be called when clicking the button', fakeAsync(() => {
  // ...nexting

  tick();

  // without waitForAsync
  expect(mock.doSomething).toHaveBeenCalledWith(f);
}));

but in this case the method never gets called.但在这种情况下,该方法永远不会被调用。

What am I doing wrong?我究竟做错了什么? What would be the correct way of testing this code without using done() ?在不使用done()的情况下测试此代码的正确方法是什么? Is it possible to use TestScheduler with this sort of anonymous subscription?是否可以将 TestScheduler 与这种匿名订阅一起使用?

In your case you need to call fixture.detectChanges to get this to work.在您的情况下,您需要调用fixture.detectChanges才能使其正常工作。

it('should be called when clicking the button', () => {
  fixture.detectChanges(); // the first call starts the lifecycle hook

  const formState: MyFormState = { name: 'my name' };
  component.submits$.next(formState);

  expect(mock.doSomething).toHaveBeenCalledWith(formState); 

});

Now to tell you why this makes it work.现在告诉你为什么这让它起作用。 The component as you are testing it includes the dom.您正在测试的组件包括 dom。 Since you set up your subscription in the ngOnInit, the ngOnInit needs to execute to set that up.由于您在 ngOnInit 中设置了订阅,因此需要执行 ngOnInit 来进行设置。

With TestBed, ngOnInit isn't called until the first fixture.detectChanges() is called.对于 TestBed,在调用第一个 fixture.detectChanges fixture.detectChanges()之前不会调用 ngOnInit。

I know you haven't asked for this next part - my suggestion is to test your component by interacting with the html. That will provide you much better unit tests.我知道您没有要求下一部分 - 我的建议是通过与 html 交互来测试您的组件。这将为您提供更好的单元测试。 This book has been the closest to what my approach is.这本书最接近我的方法。

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

相关问题 Angular 组件中的 RxJS 订阅 - RxJS subscription in Angular component Angular 中的单元测试 rxjs - Unit testing rxjs in Angular Karma Angular Testing-无法从组件调用方法(调用服务) - Karma Angular Testing - cannot call a method (that calls a Service) from component 来自组件的角度单元测试spyOn服务 - Angular unit-testing spyOn service from component Angular 2+单元测试一个服务,该服务调用一个调用httpclient的服务get - Angular 2+ Unit testing a service that calls a service that calls an httpclient get 如何做一个简单的 angular Jasmine 单元测试时使用 RXJS 使用主题的反应方法和调用服务的 stream - How to do a simple angular Jasmine Unit testing when using RXJS reactive approach using a subject and a stream that calls a service Angular 2单元测试使用Observable和Redux Rxjs选择器的服务 - Angular 2 Unit Testing a service that uses a Observable and Redux Rxjs selector Angular 单元测试 - 组件中的服务模拟 - Angular Unit Testing- Mocking of Service in component angular 使用 http 服务调用对组件进行单元测试 - angular unit testing a component with an http service call 为什么angular单元测试没有测试这个服务中订阅的内容? - Why the angular unit test is not testing the content of the subscription in this service?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM