【问题标题】:Test pipe with dependencies on services依赖于服务的测试管道
【发布时间】:2018-05-10 21:33:51
【问题描述】:

我有一个管道可以清理 HTML,如下所示:

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({
    name: 'sanitiseHtml'
})

export class SanitiseHtmlPipe implements PipeTransform {

constructor(private _sanitizer: DomSanitizer) {}

    transform(value: any): any {
      return this._sanitizer.bypassSecurityTrustHtml(value);
    }

}

我想测试如下:

describe('Pipe: Sanatiser', () => {
    let pipe: SanitiseHtmlPipe;

    beforeEach(() => {
        pipe = new SanitiseHtmlPipe(new DomSanitizer());
    });

    it('create an instance', () => {
        expect(pipe).toBeTruthy();
    }); 
});

DomSanatizer 是一个抽象类,由 typescript 通过将其传递给构造函数来自动装配:

constructor(private _sanitizer: DomSanitizer) {}

目前我收到打字稿错误:

无法创建抽象类“DomSanitizer”的实例。

有谁知道 typescript 在实例化传递给 Angular 中的构造函数的依赖项时会做什么?或者测试这种东西的方法是什么?

【问题讨论】:

标签: angular typescript dependency-injection angular2-testing angular-test


【解决方案1】:

由于你的管道中有DI,需要配置一个测试环境(test bed)来解决依赖:

import { BrowserModule, DomSanitizer } from '@angular/platform-browser';
import { inject, TestBed } from '@angular/core/testing';

describe('SanitiseHtmlPipe', () => {
  beforeEach(() => {
    TestBed
      .configureTestingModule({
        imports: [
          BrowserModule
        ]
      });
  });

  it('create an instance', inject([DomSanitizer], (domSanitizer: DomSanitizer) => {
    let pipe = new SanitiseHtmlPipe(domSanitizer);
    expect(pipe).toBeTruthy();
  })); 
});

【讨论】:

  • 我实际上通过注释掉以下行来运行测试:TestBed.resetTestEnvironment();删除它,我会标记正确
  • 我还需要添加import { BrowserModule, DomSanitizer } from '@angular/platform-browser';
  • @codeepic “new SanitiseHtmlPipe(new DomSanitizer()) 和像上面那样注入它有什么区别”它不可能使用 new 因为类是抽象的
  • @codeepic 听起来并不复杂。我不知道你所说的 模拟类及其方法 3 次 是什么意思,但我的方法是 provide 一个模拟对象,然后 spygetFullDate() 方法上使用 jasmine 并返回测试所需的内容。随意打开一个新问题并标记我
  • @Jota.Toledo 感谢spyreturnValue 的提示-我不知道-我需要查看Jasmine 文档以了解我还缺少哪些其他好东西。我重构了我的单元测试。
【解决方案2】:

以防万一有人想重用 Pipe 的构造函数,您可以使用 TestBed 来获得相同的结果:

  let pipe: SafeHtmlPipe;
  let sanitized: DomSanitizer

  beforeEach(async() => {
    TestBed.configureTestingModule({
      providers: [DomSanitizer]
    });
    sanitized = TestBed.get(DomSanitizer);
    pipe = new SafeHtmlPipe(sanitized);
  });

  it('create an instance', () => {
    expect(pipe).toBeTruthy();
  });

【讨论】:

  • 但似乎sanitized 不可用:this.sanitizer.bypassSecurityTrustHtml is not a function。这是我尝试使用管道时的错误。
  • 嗯,据我所知,这不是方法的问题,这是因为无论出于何种原因,这个函数和其他函数都是静态的,因此,你不能这样调用它们你的测试。如果我没记错的话,如果你想测试方法调用,你需要像这样模拟它们:
    TestBed.configureTestingModule({ imports: [BrowserModule], providers: [ {provide: DomSanitizer, useValue: { sanitize: () => 'safeString', bypassSecurityTrustHtml: () => 'safeString' } } ] });
  • 抱歉,抽象方法,不是静态的
  • 有没有办法注入非测试代码中实际使用的DomSanitizerImpl?
【解决方案3】:

如果您想模拟整个提供程序并且不想使用构造函数,我就是这样做的(使用 Jest,但用您的常规 jasmine.createSpyObj 替换间谍)

规格

describe("MyPipe", () => {
  let pipe: MyPipe;
  const myServiceSpy = { myFunction: jest.fn() };

  beforeEach(() => {
    jest.clearAllMocks();
    TestBed.configureTestingModule({
      providers: [
        MyPipe,
        {
          provide: MyService,
          useValue: myServiceSpy
        }
      ]
    });

    pipe = TestBed.inject(myPipe);
  });

  it("create an instance", () => {
    expect(pipe).toBeTruthy();
  });
});

管道

@Pipe({
  name: "myPipe"
})
export class MyPipe implements PipeTransform {
  constructor(private readonly myService: MyService) {}

  transform(value: Item): boolean {
    // stuff with your service
    return true;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    • 1970-01-01
    • 2014-09-04
    • 2012-10-27
    • 1970-01-01
    • 2013-06-11
    相关资源
    最近更新 更多