嘲弄儿童成分 - 角度2

Kat*_*a24 47 angular

在测试时如何模拟子组件?我有一个父组件调用,product-selected其模板如下所示:

<section id="selected-container" class="container-fluid">
    <hr/>
  <product-settings></product-settings>
  <product-editor></product-editor>
  <product-options></product-options>
</section>
Run Code Online (Sandbox Code Playgroud)

组件声明如下所示:

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 {}
Run Code Online (Sandbox Code Playgroud)

这个组件实际上只是其他组件所在的位置,可能不包含任何其他功能.

但是当我设置测试时,我得到以下模板错误,对所有三个组件重复:

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>
Run Code Online (Sandbox Code Playgroud)

我试图加载一个模拟版本的子组件但不知道该怎么做 - 我见过的例子只是覆盖了父组件,甚至没有提到子组件.那我该怎么做呢?

Arn*_*d P 78

小心一点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
});
Run Code Online (Sandbox Code Playgroud)

  • 我正在使用这样的东西来测试带有输入和输出的子组件,它非常适合验证绑定是否可以双向工作,但是,它容易出现位腐烂,作为“真实”子项中输入属性的重命名组件不会导致测试失败。我想知道是否可以通过以某种方式检查其注释来基于真实子组件生成动态 Mock 类型。由于每个子组件都可能有一组未知的依赖注入,因此它必须仅基于类型,而不是子组件的实例化版本 (2认同)

Sor*_*raz 33

找到了一个近乎完美的解决方案,如果有人重构某个组件,它也会正确地抛出错误.

npm install --only=dev ng-mocks
Run Code Online (Sandbox Code Playgroud)

现在你的.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),
      ...
Run Code Online (Sandbox Code Playgroud)

这将创建一个新的匿名组件,它具有与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);
});
Run Code Online (Sandbox Code Playgroud)


Mil*_*lad 25

通常,如果您在组件的视图中使用了一个正在测试的组件,并且您根本不想声明这些组件,因为它们可能有自己的依赖关系,以避免**某些东西不是已知元素:**错误您应该使用NO_ERRORS_SCHEMA.

import { NO_ERRORS_SCHEMA }          from '@angular/core';

TestBed.configureTestingModule({
        declarations: declarations,
        providers: providers
        schemas:      [ NO_ERRORS_SCHEMA ]
  })
Run Code Online (Sandbox Code Playgroud)

基于文档:

将NO_ERRORS_SCHEMA添加到测试模块的模式元数据中,以告知编译器忽略无法识别的元素和属性.您不再需要声明不相关的组件和指令.

更多相关信息:https://angular.io/docs/ts/latest/guide/testing.html#!#shallow-component-test

  • 编写模拟组件可能会花费您更多的时间,但最终它们都是值得的。使用 NO_ERRORS_SCHEMA 以后会困扰你 (4认同)
  • 这是一个非常糟糕的解决方案,因为它掩盖了其他潜在的问题,因此违背了测试代码的目的.Arnaud P给出了一个很好的答案. (3认同)

Kat*_*a24 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;
    });
Run Code Online (Sandbox Code Playgroud)

您必须overrideComponent为每个子组件链接函数.