You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jasmine测试Angular 5时DomSanitizer方法调用报错问题

问题:Angular 5单元测试中DomSanitizer的bypassSecurityTrustStyle不是函数的错误

我正在用Jasmine对Angular 5应用做单元测试,现在要测试一个依赖DomSanitizer的函数:

loadImage() { 
  this.image = this.sanitizer.bypassSecurityTrustStyle(`url(${this.assetUrl})`); 
}

这个函数运行正常,DomSanitizer已经注入到构造函数里,语法也没问题。

我的单元测试代码是这样的:

it('loads the Image', () => { 
  component.loadImage() 
  fixture.detectChanges(); 
  expect(component.imageUrl).toBe('...'); 
});

另外,我已经把DomSanitizer加到TestBed的providers里了:

beforeEach(async(() => { 
  TestBed.configureTestingModule({ 
    imports: [ RouterTestingModule, CommonModule ], 
    declarations: [ MyComponent ], 
    providers: [ DomSanitizer ], 
    schemas: [ NO_ERRORS_SCHEMA ] 
  }) 
  .compileComponents(); 
}));

但运行测试时Jasmine抛出错误:

ERROR: 'Unhandled Promise rejection:', '_this.sanitizer.bypassSecurityTrustStyle is not a function', '; Zone:', 'angular', '; Task:', 'Promise.then', '; Value:', TypeError: _this.sanitizer.bypassSecurityTrustStyle is not a function

求解决思路,谢谢!


回答

这个问题我之前在做Angular测试的时候也碰到过,核心原因是你直接把DomSanitizer加到TestBed的providers里是不对的——因为DomSanitizer本身是个抽象类,测试环境不会自动给它提供可用的具体实例,所以调用它的方法时才会报错。给你几个可行的解决思路:

方案1:手动Mock DomSanitizer(最推荐,测试隔离性好)

不需要依赖Angular的内部实现,自己模拟一个sanitizer对象,只实现我们需要的方法就行。这样测试的时候完全可控,还能验证方法的调用情况:

修改TestBed的providers配置:

beforeEach(async(() => { 
  TestBed.configureTestingModule({ 
    imports: [ RouterTestingModule, CommonModule ], 
    declarations: [ MyComponent ], 
    providers: [
      { 
        provide: DomSanitizer, 
        useValue: {
          // 测试里不需要真的做 sanitize,直接返回输入即可
          bypassSecurityTrustStyle: (value: string) => value 
        }
      }
    ], 
    schemas: [ NO_ERRORS_SCHEMA ] 
  }) 
  .compileComponents(); 
}));

如果想验证bypassSecurityTrustStyle是否被正确调用,还可以在测试里加个spy:

it('loads the Image and calls sanitizer correctly', () => { 
  // 获取注入的sanitizer实例
  const sanitizer = TestBed.inject(DomSanitizer);
  // 监听bypassSecurityTrustStyle方法
  spyOn(sanitizer, 'bypassSecurityTrustStyle').and.returnValue('sanitized-result');
  
  // 设置测试用的assetUrl
  component.assetUrl = 'test-image.png';
  // 调用目标函数
  component.loadImage();
  
  // 验证方法调用参数是否正确
  expect(sanitizer.bypassSecurityTrustStyle).toHaveBeenCalledWith('url(test-image.png)');
  // 验证组件的image属性是否被正确赋值
  expect(component.image).toBe('sanitized-result');
});

方案2:使用Angular的具体实现类

如果你想使用Angular真实的sanitizer逻辑,可以导入DomSanitizerImpl(这是DomSanitizer的具体实现),然后在providers里配置:

首先导入:

import { DomSanitizerImpl } from '@angular/platform-browser/src/security/dom_sanitizer';

然后修改providers:

providers: [
  { provide: DomSanitizer, useClass: DomSanitizerImpl }
]

不过要注意,DomSanitizerImpl是Angular的内部API,可能在后续版本有变动,如果你用的是Angular 5,这个是没问题的。

方案3:调整测试模块的导入

有时候导入BrowserModule可以让测试环境自动提供正确的DomSanitizer实例,不过这种方式会引入很多不必要的模块,可能让测试变慢,所以不是最优解:

imports: [ RouterTestingModule, CommonModule, BrowserModule ],

总结一下,最推荐的是方案1,既保证了测试的隔离性,又能灵活验证函数的行为,避免依赖Angular内部实现带来的风险。

内容的提问来源于stack exchange,提问作者Alex Verzea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:52:31