如何在 Jest 中对订阅可观测对象的方法进行单元测试?

16

我在组件中有各种方法订阅注入依赖项中返回 observables 的方法。

我想编写 Jest 单元测试,以确保当这些 observables 返回 / 出错时,我的方法可以正确执行。

在下面的示例中,我试图编写一个测试,检查 doAThing 是否已触发。以下两个测试都不起作用。它们都会失败,并出现类似于

'returnMyObservable.subscribe is not a function'.

// Example method to test component 
public testFunction (): void {
    this.myService.returnMyObservable.subscribe(
        ( value ) => this.doAThing( value )
    )
}
describe( 'myComponemt', () => {

    let fixture;
    let myServiceMock;

    beforeEach( () => {
        myServiceMock = {
            returnMyObservable: fn()
        }

        fixture = new myComponent( myServiceMock );
    });


    // 1) I have tried mocking with a returned value
    it ( 'should call do a thing when value is returned', () => {
        myServiceMock.returnMyOnservable.mockReturnValue( true );

        fixture.testFunction();

        expect( fixture.doAThing ).toHaveBeenCalled();
    });

    // 2) I have tried returning an observable
    it ( 'should call do a thing when value is returned', () => {
        myServiceMock.returnMyOnservable.mockReturnValue( of( true ) );

        fixture.testFunction();

        expect( fixture.doAThing ).toHaveBeenCalled();
    });

});
2个回答

9

我发现我的一些其他错误掩盖了实际出错的位置 - 我发现测试上述功能的最佳方法是:

describe( 'MyComponent', () => {
    let fixture;
    let myServiceMock;

    beforeEach( () => {
        myServiceMock = {
            returnMyObservable: jest.fn()
        }

        fixture = new MyComponent( myServiceMock );
    });

    it ( 'should call doAThing when value is returned', () => {
        const doAThingSpy = jest.spyOn( fixture, 'doAThing' );
        myServiceMock.returnMyObservable.mockReturnValue( of( true ) );

        fixture.testFunction();

        expect( doAThingSpy ).toHaveBeenCalledWith( true );
    });
});

(Jasmine中也可以用同样的方法进行操作)

我有一种稍微不同的方法,尽管我仍然觉得它有些不正确。 我使用of(value)模拟服务函数以返回我选择的可观察对象。我只是在其中调用执行订阅的组件,使用toHaveBeenCalled()测试doAThing函数,并在测试用例的末尾添加了done()。使用这种设置似乎所有测试都通过了。 - Qarun Qadir Bissoondial

5
我们可以使用 mockImplementation 来模拟 this.myService.returnMyObservable 的实现。之后,我们可以在测试用例(observer)中获取您传递给 subscribe 的函数,然后手动执行它。
以下是解决方案: index.ts:
export class MyComponent {
  private myService;
  constructor(myService) {
    this.myService = myService;
  }
  public testFunction(): void {
    this.myService.returnMyObservable.subscribe(value => this.doAThing(value));
  }
  public doAThing(value) {}
}

index.spec.ts:

import { MyComponent } from './';

describe('MyComponent', () => {
  let fixture;
  let myServiceMock;

  beforeEach(() => {
    myServiceMock = {
      returnMyObservable: {
        subscribe: jest.fn()
      }
    };
    fixture = new MyComponent(myServiceMock);
  });

  it('should call do a thing when value is returned', () => {
    let observer;
    myServiceMock.returnMyObservable.subscribe.mockImplementation(handler => {
      observer = handler;
    });
    jest.spyOn(fixture, 'doAThing');
    fixture.testFunction();
    observer();

    expect(fixture.doAThing).toHaveBeenCalled();
  });
});

100%覆盖率的单元测试结果:

 PASS  src/stackoverflow/58815471/index.spec.ts (7.367s)
  MyComponent
    ✓ should call do a thing when value is returned (5ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.ts |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        8.773s

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58815471

你好,感谢您的回复。我现在遇到了错误 TypeError: observer is not a function - TheRyanSmee
@TheRyanSmee 请检查你的代码。我的答案的代码运行良好。 - Lin Du
再次感谢您的耐心等待。我能看出来为什么我的代码失败了而你的没有。在你的示例中,你正在服务中订阅一个Observable。而我正在订阅从方法返回的Observable。 如果你将你的服务更改为以下代码,你就会看到错误。 public returnMyObservable (): Observable<boolean> { return of( true ); } 你知道如何为返回Observable的方法编写测试吗? - TheRyanSmee
我应该补充说明,如果doAThing内部有需要从订阅块中获取value的函数,则应该使用该参数调用observerobserver(value) - Qarun Qadir Bissoondial

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接