【问题标题】:How do I go about testing a Pipe which depends on DomSanitizer?如何测试依赖于 DomSanitizer 的 Pipe?
【发布时间】:2023-03-23 21:37:01
【问题描述】:

Angular 版本:8.1.2
测试工具:Karma 和 Jasmine,由 ng new 预装

我目前正在从事我的第一个 Angular 项目。作为其中的一部分,我创建了一个调用DomSanitizer.bypassSecurityTrustResourceUrl 的管道。我这样做是为了能够在 iframe 中使用它们。我现在想为此管道实施测试。这是它的代码:

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

@Pipe({
  name: 'safe'
})
export class SafeResourceUrlPipe implements PipeTransform {

  constructor(private sanitizer: DomSanitizer) { }

  transform(url: string): SafeResourceUrl | string {
    return this.sanitizer.bypassSecurityTrustResourceUrl(url);
  }

}

自动生成的规范文件看起来像这样:

import { TestBed, async } from '@angular/core/testing';
import { SafeResourceUrlPipe } from './safe-resource-url.pipe';
import { DomSanitizer } from '@angular/platform-browser';

describe('Pipe: SafeResourceUrle', () => {
  it('should create an instance', () => {
    let pipe = new SafeResourceUrlPipe();
    expect(pipe).toBeTruthy();
  });
});

这不起作用 VSCode 在我运行测试之前告诉我,因为SafeResourceUrlPipe 的构造函数需要一个参数。到目前为止一切顺利,但我不知道现在该怎么办。我不能只使用new DomSanitizer,因为它是一个抽象类。

我尝试的是创建一个实现 DomSanitizer 的模拟类,但是我只能测试是否创建了管道,而且我之前已经知道这一点。我想测试的是它是否正确地完成了转换输入的工作,但是当我伪实现主要依赖项时,我几乎无法测试。

我已经对此进行了一些谷歌搜索,我怀疑结果会很明显,但我找不到。

【问题讨论】:

    标签: angular abstract-class angular-test angular-dom-sanitizer


    【解决方案1】:

    你不需要模拟DomSanitizer,当你导入BrowserModule时它就可用了。所以你只需要在配置测试模块的时候导入这个模块,然后用TestBed.get()方法取回它就可以传递给你的管道构造器。

    import { BrowserModule, DomSanitizer } from '@angular/platform-browser';
    
    describe('Pipe: SafeResourceUrl', () => {
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          imports: [BrowserModule],
        });
      });
    
      it('should create an instance', () => {
        const domSanitizer = TestBed.get(DomSanitizer);
        const pipe = new SafeResourceUrlPipe(domSanitizer);
        expect(pipe).toBeTruthy();
      });
    });
    

    【讨论】:

    • const domSanitizer = TestBed.inject(DomSanitizer);从现在开始
    【解决方案2】:

    我建议使用 Angular Testbed 来注入这样的 dom sanitizer 的模拟。

    beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [SafeResourceUrlPipe],
          providers: [
               SafeResourceUrlPipe,
              { provide: DomSanitizer, useValue: {bypassSecurityTrustResourceUrl(){}}
         ]
        });
      }));
    

    然后

    describe('Pipe: SafeResourceUrle', () => {
      it('should create an instance', () => {
        let pipe = TestBed.get(SafeResourceUrlPipe);
        expect(pipe).toBeTruthy();
      });
    });
    

    附言useValue 在这里很重要。如果您只在此处提供一个值,则可以。如果你想用一个完整的模拟类替换它,你必须useClass(大多数人都会卡住的小错误)

    export class MockDomSanitizer {
        bypassSecurityTrustResourceUrl() {}
        otherMethods(){}
    }
    

    这应该允许您使用模拟出来的 dom sanitizer 方法运行管道。

    【讨论】:

    • 感谢您的回答,尽管我认为您错过了一些东西。起初,在尝试你的提示时,我得到了一个NullInjectorError: No provider for SafeResourceUrlPipe,但在providers 中添加SafeResourceUrl 修复了它。然而,我还有另一个问题:我可以用这个实际测试我的管道的transform 方法吗?如果不能,我怎么能做到这一点?
    • 哎呀,是的,我认为它可能必须进入供应商(也)。那是我想知道的另一件事。为什么需要测试它?在单元测试实践中,您真的不需要测试这个,因为您正在测试 Angular 代码而不是您自己的代码?
    • 是的,我之前也注意到了这一点,但由于我是初学者,我认为无论如何了解一下可能会有所帮助。如果我将来遇到我自己的代码足够复杂以保证测试(在这种情况下)transform 方法的情况,那么我需要使用(在这种情况下)DomSanitizer 及其实际可用的方法。然后我当然可以尝试模拟这个类,但由于它是抽象的,所以我不知道它实际上是如何“在引擎盖下”工作的。我认为对于这个更简单的情况,解决这个问题可能会更好,尽管具体来说这并不重要。
    • 是的,我认为这是一个足够公平的思考过程。但是,您在模拟时不应该需要关心内部实现。这就是重点。你只需告诉一个外部函数返回你想要的任何东西(你只需要知道返回类型)然后你就可以测试你的函数了。例如...当这个外部函数返回“Hello World”时,我希望我的函数返回 true。我们不应该关心它是如何做到的,我们只关心 your 函数的行为是否符合您的预期。希望我说得通
    • 你可能是对的。特别是 DomSanitizer 并不能真正使用它,因为它的方法返回的类型真的很奇怪,但话又说回来,我只是注意到你可能永远不会在它们被创建之后再触摸它们,然后将它们直接插入 HTML .感谢您的耐心等待!
    猜你喜欢
    • 2017-07-08
    • 2018-06-24
    • 2013-03-10
    • 2019-11-19
    • 2012-01-28
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多