我目前正在我的角度应用程序中实施“单元测试”。但是,如果我运行它们,则会收到类似于以下警告/错误的多个警告/错误:'Error retrieving icon: Unable to find icon with the name ":myIcon"'
。我怀疑这可能是由于未将svg添加到我的MatIconRegistry中引起的。我通常在我的AppComponent中这样做,就像这样:
constuctor(private iconRegistry: MatIconRegistry,
private sanitizer: DomSanitizer,
...) {
iconRegistry.addSvgIcon('myIcon', sanitizer.bypassSecurityTrustResourceUrl('./assets/icons/myIcon.svg'));
}
但是,如果我运行另一个组件的单元测试,它将不会执行,因此不会将我的svg添加到注册表中。我已经尝试将其添加到相应组件的.spec文件中,如下所示:
fdescribe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let iconRegistry;
let sanitizer;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
...
],
imports: [
...
],
providers: [
...
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
iconRegistry = TestBed.get(MatIconRegistry);
sanitizer = TestBed.get(DomSanitizer);
iconRegistry.addSvgIcon('myIcon', sanitizer.bypassSecurityTrustResourceUrl('./../../assets/icons/myIcon.svg'));
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create component', () => {
expect(component).toBeTruthy();
});
});
如果我运行此命令,它将不起作用。它只是返回不同的错误消息:
Error retrieving icon: <svg> tag not found
我最初的想法是我在路径上犯了一个错误,但是尝试了其他各种路径后,我确定情况并非如此。
有人知道如何解决这个问题吗?或者也许有更好的方法,因为我必须在要测试的每个组件中添加svg图标,这有点多余。
答案 0 :(得分:13)
可以做到:
...
import { MatIcon } from '@angular/material/icon';
import { MatIconTestingModule } from '@angular/material/icon/testing';
describe('MyComponent', () => {
...
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyComponent, MatIcon],
imports: [MatIconTestingModule],
}).compileComponents();
}));
...
});
这将在没有http请求的情况下生成测试图标渲染
答案 1 :(得分:3)
模拟mat-icon
选择器,并在单元测试的顶部添加以下组件
@Component({
selector: 'mat-icon',
template: '<span></span>'
})
class MockMatIconComponent {
@Input() svgIcon: any;
@Input() fontSet: any;
@Input() fontIcon: any;
selector: 'mat-icon',
template: '<span></span>'
})
然后按如下所示在单元测试中覆盖MatIconModule
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ ...],
providers: [ ... ],
imports: [ MatIconModule, NoopAnimationsModule ]
})
.overrideModule(MatIconModule, {
remove: {
declarations: [MatIcon],
exports: [MatIcon]
},
add: {
declarations: [MockMatIconComponent],
exports: [MockMatIconComponent]
}
})
.compileComponents();
运行单元测试时,您将不再遇到'Error retrieving icon: Unable to find icon with the name ":myIcon"'
问题
答案 2 :(得分:3)
为此花了几个小时。看起来Angular现在提供了FakeMatIconRegistry
。它减少了约90%的业障警告,但仍然有一些...
要做很多这样的事情:
TestBed.configureTestingModule({
declarations: [ MyComponent ],
imports: [
...
MatIconModule,
],
providers: [
...
{ provide: MatIconRegistry, useClass: FakeMatIconRegistry }
]
}).compileComponents();
答案 3 :(得分:0)
使用typemoq进行模拟;以下对我有用:
const mockIconRegistry = Mock.ofType<MatIconRegistry>();
mockIconRegistry.setup(s => s.getNamedSvgIcon(It.isAny(), It.isAny())).returns(() => of(Mock.ofType<SVGElement>().object));
然后
providers: [{ provide: MatIconRegistry, useFactory: () => mockIconRegistry.object }]
答案 4 :(得分:0)
您可以做的是安装ng-mocks并使用 MockModule 在测试中模拟MatIconModule,例如:
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MockModule(MatIconModule)],
}).compileComponents();
}));
答案 5 :(得分:0)
还有另一种方法来避免此问题。 Spectator(这是Angular单元测试中非常棒的工具)具有方便的 shallow 标志,该标志基本上可以防止所有子组件(包括mat-icon)被编译,但可以作为简单的HTML标记进行处理代替。
const createComponent = createComponentFactory({
component: MyComponent,
imports: [
...
],
mocks: [
...
],
providers: [
...
],
shallow: true // <-- ignore child components
});
启用此标志后,您不再需要导入MatIconModule ,也减少了测试运行时间,因为Angular在运行测试。这样一来,您就可以在编写单元测试时真正专注于组件本身,而不必担心您根本不需要的东西。
如果你问我,这是双赢的:)