测试时如何模拟子组件?我有一个名为product-selected
的父组件,其模板如下所示:
<section id="selected-container" class="container-fluid">
<hr/>
<product-settings></product-settings>
<product-editor></product-editor>
<product-options></product-options>
</section>
组件声明如下所示:
import { Component, Input } from '@angular/core';
import { ProductSettingsComponent } from '../settings/product-settings.component';
import { ProductEditorComponent } from '../editor/product-editor.component';
import { ProductOptionsComponent } from '../options/product-options.component';
@Component({
selector: 'product-selected',
templateUrl: './product-selected.component.html',
styleUrls: ['./product-selected.component.scss']
})
export class ProductSelectedComponent {}
这个组件实际上只是其他组件所在的位置,可能不会包含任何其他功能。
但是当我设置测试时,我得到以下模板错误,对所有三个组件重复:
Error: Template parse errors:
'product-editor' is not a known element:
1. If 'product-editor' is an Angular component, then verify that it is part of this module.
2. If 'product-editor' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message. ("
<hr/>
<product-settings></product-settings>
[ERROR ->]<product-editor></product-editor>
我试图加载儿童组件的模拟版本,但不知道该怎么做 - 我见过的例子只是覆盖了父母,甚至没有提到儿童组成部分。那我该怎么做呢?
答案 0 :(得分:68)
小心NO_ERRORS_SCHEMA
。让我们引用相同文档的另一部分:
使用NO_ERRORS_SCHEMA进行浅组件测试可大大简化复杂模板的单元测试。但是,编译器不再警告您错误,例如拼写错误或误用的组件和指令。
我发现这个缺点与编写测试的目的完全相反。更重要的是,嘲笑基本组件并不难。
此处尚未提及的方法只是在配置时声明它们:
@Component({
selector: 'product-settings',
template: '<p>Mock Product Settings Component</p>'
})
class MockProductSettingsComponent {}
@Component({
selector: 'product-editor',
template: '<p>Mock Product Editor Component</p>'
})
class MockProductEditorComponent {}
... // third one
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
ProductSelectedComponent,
MockProductSettingsComponent,
MockProductEditorComponent,
// ... third one
],
providers: [/* your providers */]
});
// ... carry on
});
答案 1 :(得分:25)
找到了一个近乎完美的解决方案,如果有人重构某个组件,它也会正确地抛出错误。
npm install ng-mocks
现在在你的.spec.ts中你可以做到
import { MockComponent } from 'ng-mocks';
import { ChildComponent } from './child.component.ts';
...
beforeEach(
async(() => {
TestBed.configureTestingModule({
imports: [FormsModule, ReactiveFormsModule, RouterTestingModule],
declarations: [
ComponentUnderTest,
MockComponent(ChildComponent),
...
这将创建一个新的匿名组件,该组件具有与ChildComponent相同的选择器,@ Input()和@Output()属性,但没有附加代码。
假设您的ChildComponent有一个@Input() childValue: number
,它绑定在您测试的组件中,<app-child-component [childValue]="inputValue" />
到目前为止,我发现的唯一不足之处是,您在测试中无法使用By.directive(ChildComponent)
,因为类型会发生变化,但您可以使用By.css('app-child-component')
这样的
it('sets the right value on the child component`, ()=> {
component.inputValue=5;
fixture.detectChanges();
const element = fixture.debugElement.query(By.css('app-child-component'));
expect(element).toBeTruthy();
const child: ChildComponent = element.componentInstance;
expect(child.childValue).toBe(5);
});
答案 2 :(得分:24)
通常,如果你正在测试的组件视图中使用了一个组件,并且你根本不想声明那些组件,因为它们可能有自己的依赖关系,以避免**某事不是已知元素:**错误您应该使用 NO_ERRORS_SCHEMA 。
import { NO_ERRORS_SCHEMA } from '@angular/core';
TestBed.configureTestingModule({
declarations: declarations,
providers: providers
schemas: [ NO_ERRORS_SCHEMA ]
})
基于文档:
将NO_ERRORS_SCHEMA添加到测试模块的模式元数据中,以告知编译器忽略无法识别的元素和属性。您不再需要声明不相关的组件和指令。
更多相关信息:https://angular.io/docs/ts/latest/guide/testing.html#!#shallow-component-test
答案 3 :(得分:9)
我发布了这个问题所以我可以在一两天内努力解决这个问题。以下是您的工作方式:
let declarations = [
ProductSelectedComponent,
ProductSettingsComponent,
ProductEditorComponent,
ProductOptionsComponent
];
beforeEach(() => {
TestBed.configureTestingModule({
declarations: declarations,
providers: providers
})
.overrideComponent(ProductSettingsComponent, {
set: {
selector: 'product-settings',
template: `<h6>Product Settings</h6>`
}
})
.overrideComponent(ProductEditorComponent, {
set: {
selector: 'product-editor',
template: `<h6>Product Editor</h6>`
}
})
.overrideComponent(ProductOptionsComponent, {
set: {
selector: 'product-options',
template: `<h6>Product Options</h6>`
}
});
fixture = TestBed.createComponent(ProductSelectedComponent);
cmp = fixture.componentInstance;
de = fixture.debugElement.query(By.css('section'));
el = de.nativeElement;
});
您必须为每个子组件链接overrideComponent
函数。