【问题标题】:Angular 8 Unit test EventSource using Jasmin使用 Jasmin 的 Angular 8 单元测试 EventSource
【发布时间】:2020-08-22 07:41:41
【问题描述】:

我在我的应用程序中使用了 EventSource 并编写了如下所示的包装服务:

import { Injectable } from '@angular/core';
import { EventSourcePolyfill } from 'event-source-polyfill';
import { Observable } from 'rxjs';
import { AppConstants } from 'src/app/framework/constants/app.constants';

const base_url = `${AppConstants.REST_API_URL}datacontrolmanagment/notification`;

@Injectable({
  providedIn: 'root'
})
export class SseService {

  private eventSource;
  constructor() { }


  /**
   * 
   * @param url for Event Source Endpoint
   * @param headers passing authorization token
   */
  private getEventSource(headers) {
    return new EventSourcePolyfill(base_url, headers)
  }

  public getServerSentEvents(headers) {
    return Observable.create(observer => {
      if (!(this.eventSource instanceof EventSourcePolyfill)) {
        this.eventSource = this.getEventSource(headers);
      }

      this.eventSource.onmessage = msg => {
        console.log(msg)
        observer.next(msg);
      };

      this.eventSource.onerror = msg => {

      }; 

    });

  };

  public closeEventSource() {
    if ((this.eventSource instanceof EventSourcePolyfill)) {
      this.eventSource.close();
    }
  }
}

我已在我的一个组件中使用此服务。

为了代码覆盖率,我想测试此服务。 但是我无法弄清楚如何测试上面的代码。

我尝试创建 EventSource 的模拟/虚拟类,但没有成功

注意:我已经测试过这个服务的组件代码。

【问题讨论】:

    标签: angular typescript jasmine karma-jasmine


    【解决方案1】:

    因为目前EventSourcePolyfillSseService 的内部部分,所以您根本不应该嘲笑它。例如,如果它是构造函数传递的依赖项,则可以模拟它。

    这里有 2 个选项 - 创建一个工厂令牌,而不是提供 EventSourcePolyfill,然后你可以模拟它。

    或者简单地覆盖getServerSentEvents 的发射,就像EventSourcePolyfill 一样。 你可以在问题中分享它的代码吗?

    对于第一种情况,您可以下一步(这是一个示例,而不是工作副本)

    const base_url = `${AppConstants.REST_API_URL}datacontrolmanagment/notification`;
    
    export const ESP = new InjectionToken<(headers: any) => EventSourcePolyfill>('ESP', {
        factory: () => headers => new EventSourcePolyfill(base_url, headers),
    });
    
    @Injectable({
      providedIn: 'root'
    })
    export class SseService {
    
      private eventSource;
      constructor(@Inject(ESP) private eventSourceFactory: (headers: any) => EventSourcePolyfill) {}
    
      public getServerSentEvents(headers) {
        return Observable.create(observer => {
          if (!(this.eventSource instanceof EventSourcePolyfill)) {
            this.eventSource = this.eventSourceFactory(headers);
          }
    
          this.eventSource.onmessage = msg => {
            console.log(msg)
            observer.next(msg);
          };
    
          this.eventSource.onerror = msg => {
    
          }; 
    
        });
    
      };
    
      public closeEventSource() {
        if ((this.eventSource instanceof EventSourcePolyfill)) {
          this.eventSource.close();
        }
      }
    }
    

    现在你可以这样模拟它了

    it('', done => {
      const mockESP: any = jasmine.createSpyObj('EventSourcePolyfill', ['onmessage', 'onerror', 'close']);
    
      const mockFactory: any = jasmine.createSpy('EventSourceFactory');
      mockFactory.and.returnValue(mockESP);
    
      const service = new SseService(mockFactory);
      service.getServerSentEvents({myHeaders: true}).subscribe(result => {
        expect(result).toBe('test');
        done();
      });
      mockESP.onmessage.calls.argsFor(0)[0]('test');
      expect(mockESP).toHaveBeenCalledWith({myHeaders: true});
    }
    

    【讨论】:

    • EventSourcePolyfill 只是 MDN 中定义的 EventSource 上的第 3 方 npm 包,用于传递自定义标头。
    • 啊哈,我明白了,那么一定要尝试用工厂添加ESP 令牌,这样就可以模拟它。
    • 会试一试
    • 我也遇到了同样的情况,解决方法有效吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 1970-01-01
    • 2014-05-11
    • 2021-11-16
    相关资源
    最近更新 更多